使用std :: is_same和operator ||进行编译错误

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用std :: is_same和operator ||进行编译错误相关的知识,希望对你有一定的参考价值。

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

(这不是'真正的'答案,但使用答案比使用评论更实际)

我对你的代码有相同的行为,但奇怪的是没有警告/错误替换

return dynamic_cast<const Base*>(&object) != nullptr;

通过

const T * pobject = &object;

return std::is_same<Base, T>::value || dynamic_cast<const Base*>(pobject) != nullptr;

#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;
}

编译(gcc版本6.3.0)

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra -Wall -Werror b.cc
pi@raspberrypi:/tmp $ 
另一答案

此代码不会给您一个错误,而是一个警告。在我看来,它在这里很有帮助。警告是你可以选择忽略的东西,但在这种情况下,它正在提出一个有用的观点:dynamic_casting一个类型到它的基类将永远不会返回一个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缺陷的情况,告诉你在某些模板实例化下不会执行的代码。

另一答案

以下代码也编译时没有警告:

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)出现问题

目前我选择了“三元运算符”变体,但我喜欢“两个函数”之一。

另一答案

我认为c ++ 17解决方案也可以

if constexpr (std::is_same<Base, T>::value) {
  return true;
} else {
  return dynamic_cast<const Base*>(&object) != nullptr;
}

以上是关于使用std :: is_same和operator ||进行编译错误的主要内容,如果未能解决你的问题,请参考以下文章

C++11的std::is_same和std::decay使用与源码解析

模板编程之std::is_same和std::decay

is_same 上的 Cppcheck 语法错误与模板

在 vc++ 中使用模板限制类型

std::vector::insert 与 std::list::operator[]

cppyy 和 std::is_same_v (C++17)