This is probably a duplicate, but I just can't find one where the OP clearly has the same problem I'm having.
I have a class, and I'm trying to enable operator-
only if the class template parameter is not an unsigned type.
#include <type_traits>
template<class T>
struct A {
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
};
int main() {
A<unsigned> a=a;
}
Unfortunately, this produces a compiler error any time I instantiate it with an unsigned type as shown.
main.cpp:5:29: error: no type named 'type' in 'std::enable_if<false, A<unsigned int> >'; 'enable_if' cannot be used to disable this declaration
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:9:17: note: in instantiation of template class 'A<unsigned int>' requested here
A<unsigned> a=a;
^
Well, I can clearly see that enable_if
is not going to work here. One vaguely similar question mentioned I can use inheritance and template specialization to work around this, but... is there really no better way?
I had the same problem once. Turns out there can't be a substitution failure since the default template argument doesn't depend on a template parameter from the function template. You have to have a template argument defaulted to the enclosing template type, like this:
template<typename U = T,
class = typename std::enable_if<!std::is_unsigned<U>::value, U>::type>
A operator-() { return {}; }
A bit long for a comment: You can also use a free function, even for unary operators.
#include <type_traits>
template<class T>
struct A {
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T>) {return {};}
int main() {
A<signed> b;
-b; // ok
A<unsigned> a;
-a; // error
}
This doesn't introduce a member function template for each class template.
Here's how you can befriend it:
template<class T>
class A {
int m;
public:
A(T p) : m(p) {}
template<class U>
friend
typename std::enable_if<!std::is_unsigned<U>::value,A<U>>::type
operator-(A<U>);
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T> p) {return {p.m};}
int main() {
A<signed> b(42);
-b; // ok
A<unsigned> a(42);
//-a; // error
}
You can (should) forward-declare that function template, though.
One possible way is introducing a dummy template parameter:
template<class T>
struct A {
template<
typename D = int,
typename = typename std::enable_if<!std::is_unsigned<T>::value, D>::type
>
A operator-() {return {};}
};
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