考虑以下代码:
template <typename T> using VoidT = void;
class A {
public:
using TEST = int;
};
class C {
public:
using DIFFERENT = int;
};
template <typename T, typename Enable = void>
class B {
public:
B() = delete;
};
template <typename T>
class B<T, VoidT<typename T::TEST>> {
public:
B() = default;
};
template <typename T>
class B<T, VoidT<typename T::DIFFERENT>> {
public:
B() = default;
};
int main() {
B<A> a;
B<C> b;
return 0;
}
使用g ++-4.8.5,编译此代码会给我以下错误消息:
~/test/compile_test> g++ -std=c++11 test.cpp
test.cpp:31:7: error: redefinition of ‘class B<T, void>’
test.cpp:24:7: error: previous definition of ‘class B<T, void>’
但是,当我使用g ++-8.3(例如ideone)进行编译时,代码会编译,并且正确处理了不同的专业领域。是在GCC中修复了一个错误,还是我以某种方式调用了未定义的行为(因此,编译器行为的差异是有争议的-它是未定义的)?
答案 0 :(得分:9)
这是否已解决了GCC中的错误?
这是标准中的缺陷。它已针对以前的标准版本进行了追溯修复,但当然只有较新的编译器版本才具有此修复程序。是CWG Issue 1558,并引用它:
别名模板特化中未使用参数的处理 当前的17.6.7 [温度别名]未指定。对于 例如:
#include <iostream> template <class T, class...> using first_of = T; template <class T> first_of<void, typename T::type> f(int) { std::cout << "1\n"; } template <class T> void f(...) { std::cout << "2\n"; } struct X { typedef void type; }; int main() { f<X>(0); f<int>(0); }
是对first_of的引用,其中T为int 等同于简单地作废,还是替代失败?
没有DR修复程序的编译器的解决方法是使用帮助程序:
template<typename T> struct voider { using type = void; };
template <typename T> using VoidT = typename voider<T>::type;
在类模板中可以确保替换失败。