我不明白为什么下面的代码可以用Clang ++编译,而不能用g ++编译。
#include <memory>
class A {
public:
virtual ~A() {}
};
class B : public A {
public:
virtual ~B() {}
};
template <typename Base, typename T>
inline bool isInstanceOf(const T& object) {
// This line compiles with clang++ (7.0.1) and with gcc (8.3.1)
// return std::is_same<Base, T>::value ? true : (dynamic_cast<const Base*>(&object) != nullptr);
// This line compiles only with clang++
return std::is_same<Base, T>::value || dynamic_cast<const Base*>(&object) != nullptr;
}
int main() {
isInstanceOf<A>(B());
isInstanceOf<A>(A()); // Compilation fails
return 0;
}
编译错误:
$> g++ -o bin -Wall -Werror test.cpp
test.cpp: In instantiation of 'bool isInstanceOf(const T&) [with Base = A; T = A]':
test.cpp:24:24: required from here
test.cpp:19:79: error: the compiler can assume that the address of 'object' will never be NULL [-Werror=address]
std::is_same<Base, T>::value || dynamic_cast<const Base*>(&object) != nullptr;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
cc1plus: all warnings being treated as errors
为什么模板实例化不跳过测试的第二部分?
以下代码也可以编译:
if (std::is_same<Base, T>::value) {
return true;
} else {
return dynamic_cast<const Base*>(&object) != nullptr;
}
以下代码的编译也将失败:
if (std::is_same<Base, T>::value) {
return true;
}
return dynamic_cast<const Base*>(&object) != nullptr;
答案 0 :(得分:0)
(这不是“真”答案,但是使用答案比使用备注更实用)
我的代码与您的行为相同,但奇怪的是没有警告/错误替换
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script> $(document).ready(function(){ $("#hide").click(function(){ $(".someclass .wehide").hide(); }); $("#show").click(function(){ $(".someclass .wehide").show(); }); }); </script> </head> <body> <div class="someclass"> <span class="wehide">If you click on the "Hide" button, I will disappear.</span> <br/> <span class="wedont">If you click on the "Hide" button, I WILL NOT disappear.</span> <button id="hide">Hide</button> <button id="show">Show</button> </div> </body> </html>
作者
return dynamic_cast<const Base*>(&object) != nullptr;
const T * pobject = &object;
return std::is_same<Base, T>::value || dynamic_cast<const Base*>(pobject) != nullptr;
编译(gcc版本6.3.0)
#include <memory>
class A {
public:
virtual ~A() {}
};
class B : public A {
public:
virtual ~B() {}
};
template <typename Base, typename T>
inline bool isInstanceOf(const T& object) {
const T * pobject = &object;
return std::is_same<Base, T>::value || dynamic_cast<const Base*>(pobject) != nullptr;
}
int main() {
isInstanceOf<A>(B());
isInstanceOf<A>(A()); // Compilation fails
return 0;
}
答案 1 :(得分:0)
此代码不是给您一个错误,而是一个警告。在我看来,这对您有所帮助。您可以选择忽略警告,但是在这种情况下,警告很有用:dynamic_cast
将类型设为其基类将永远不会返回NULL
,并且由于这是引用类型,编译器希望在获取地址时不是NULL
指针。
此代码:
if (std::is_same<Base, T>::value) {
return true;
} else {
return dynamic_cast<const Base*>(&object) != nullptr;
}
...之所以进行编译,是因为现在您正在引入dynamic_cast
可能确实会返回NULL
的情况,因为可能无法强制转换为Base
。没错,G ++在这里没有警告您。
对我来说,这是GCC向您提供比Clang更完整的警告的情况,而不是GCC不足以告诉您在某些模板实例化下无法执行的代码的情况。
答案 2 :(得分:0)
以下代码也将在没有警告的情况下进行编译:
template <typename Base, typename T>
bool isInstanceOf(const T& object) {
if (!std::is_same<Base, T>::value) {
return dynamic_cast<const Base*>(&object) != nullptr;
}
}
或者这个:
template <typename Base, typename T>
inline bool isInstanceOf(const T* pointer) {
return dynamic_cast<const Base*>(pointer) != nullptr;
}
template <typename Base, typename T>
inline bool isInstanceOf(const T& object) {
return std::is_same<Base, T>::value || isInstanceOf<Base>(&object);
}
@cyberbisson:您可能是对的,应该是GCC进行的代码分析中所欠缺的。
我不确定什么是解决我的问题(或更具可读性/可理解性)的最佳语法。 “ if / else”选项导致clang-tidy(readability-else-after-return)问题
当前,我选择了“三元运算符”变体,但我喜欢“两个函数”之一。
答案 3 :(得分:0)
我认为c ++ 17解决方案也很好
if constexpr (std::is_same<Base, T>::value) {
return true;
} else {
return dynamic_cast<const Base*>(&object) != nullptr;
}