I'm trying to conditionally instantiate an extra assignment operator. The code below works fine in clang, but not in gcc 4.7.
The problem I'm having seems very similar the the question asked here: std::enable_if to conditionally compile a member function
The following illustrates the problem I'm having:
#include <type_traits>
template<typename T>
struct StrangerTypeRules;
template<typename T>
struct X;
template< >
struct StrangerTypeRules < unsigned > {
typedef unsigned type;
};
template< >
struct StrangerTypeRules < bool > {
typedef X<bool> type;
};
template<typename T>
struct X {
// In the non-trivial version of my code, I can not use the
// default assignment operator, therefor I need to define this one
X& operator=( const X<T>& rhs ) {
return *this;
}
// Alternative assignment oprtator, must only exists if it is
// different from the assignment operator above
template<typename =
typename std::enable_if<
( !std::is_same<
X<T>,
typename StrangerTypeRules<T>::type
>::value ),
X<T>
>::type
>
X<T> & operator=( const typename StrangerTypeRules <T>::type& rhs ) {
return *this;
}
};
int main(int argc, const char *argv[])
{
X<unsigned> x1, x2;
x1 = 4;
x2 = x1;
X<bool> x3, x4; // compile error in gcc 4.7 with -std=c++11
//x3 = x4;
return 0;
}
Can this be done in a way which satisfies both clang and gcc 4.7? If so, how?
Compilations error when using gcc:
test.cxx: In instantiation of ‘struct X<bool>’:
test.cxx:52:13: required from here
test.cxx:38:12: error: no type named ‘type’ in ‘struct std::enable_if<false, X<bool> >’
You need to make the enable_if
dependent on a template parameter. As it is now, it is only dependent on the outer template parameter within the template definition. But if you instantiate a class from the outer template, then your assignment operator template that is instantiated into that class is not dependent on a template parameter anymore because T
will have been substituted already.
Just introduce a dummy parameter equal to T
template<typename T1 = T, typename =
typename std::enable_if<
( !std::is_same<
X<T1>,
typename StrangerTypeRules<T1>::type
>::value ),
X<T1>
>::type
>
X<T1> & operator=( const typename StrangerTypeRules <T1>::type& rhs ) {
return *this;
}
Using T1
in just one of theplaces within the enable_if<...>
template arguments would suffice already, because that already makes the enable_if
dependent.
However it is not the call to your operator=
that was previously illformed but the declaration of it, which conflicts with the copy-assignment operator, so the enable_if
has little utility here. Just replace your code by
template<typename T1 = T>
X<T1> & operator=( const typename StrangerTypeRules <T1>::type& rhs ) {
return *this;
}
Since this operator=
is a template, it will not conflict with the non-template overload. And also because it is a template, when you call it the compiler will prefer the non-template if T
is X<T>
.
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