I'm trying to overload operator T()
using SFINAE to return a copy when T
is a fundamental type, and a const reference when T
is a class.
When using a double
in my example below, I can't get the 2nd overload (with std::is_class
) to be removed.
That is, the error I'm getting is:
error: no type named ‘type’ in ‘struct std::enable_if<false, const double&>’
operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
^
What am I doing wrong?
#include <iostream>
#include <type_traits>
template<typename T>
struct Foo
{
operator typename std::enable_if<!std::is_class<T>::value, T >::type () const
{
return _val;
}
operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
{
return _val;
}
T _val;
};
int main()
{
Foo<double> f1;
f1._val = 0.3;
double d = f1;
std::cout << d << std::endl;
return 0;
}
T
is already known at the time your class member functions are instantiated, so no substitution occurs, and instead of SFINAE, you get a hard error. The easiest workaround is to introduce a dummy template parameter for those operator overloads and default it to T
so that type deduction can still occur.
template<typename U = T>
operator typename std::enable_if<!std::is_class<U>::value, U >::type () const
{
return _val;
}
template<typename U = T>
operator typename std::enable_if< std::is_class<U>::value, const U&>::type () const
{
return _val;
}
Live demo
Whilst not solving the problem of why the incorrect operator was not discarded, to solve the particular issue at hand, that is, to return by const ref for class types or by value for others, a solution can be found using std::conditional
.
template< bool B, class T, class F >
struct conditional;
Provides member typedef type, which is defined as T if B is true at compile time, or as F if B is false.
Working example:
#include <iostream>
#include <type_traits>
template<typename T>
struct Foo
{
operator typename std::conditional<
std::is_class<T>::value, const T&, T>::type () const
{
return _val;
}
T _val;
};
int main()
{
Foo<double> f1;
f1._val = 0.3;
double d = f1;
std::cout << d << std::endl;
return 0;
}
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