Consider the following code:
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;
}
Using g++-4.8.5, compiling this code gives me the following error message:
~/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>’
However, when I compile using g++-8.3 (in, e.g., ideone) the code compiles and the different specializations are treated correctly. Was this a bug in GCC that was fixed, or am I somehow invoking undefined behavior (and therefore the difference in compiler behavior is a moot point - it's undefined)?
Was this a bug in GCC that was fixed?
It was a defect in the standard. It was fixed retroactively for previous standard versions, but of course only newer compiler versions will have the fix. It was CWG Issue 1558, and to quote from it:
The treatment of unused arguments in an alias template specialization is not specified by the current wording of 17.6.7 [temp.alias]. For example:
#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); }
Is the reference to first_of with T being int equivalent to simply void, or is it a substitution failure?
The workaround for compilers without the DR fix is to use a helper:
template<typename T> struct voider { using type = void; };
template <typename T> using VoidT = typename voider<T>::type;
Substitution failure is guaranteed in a class template.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With