std :: is_same和运算符||的编译错误

时间:2019-04-25 16:19:51

标签: c++11 g++ clang++

我不明白为什么下面的代码可以用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;

4 个答案:

答案 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;
}