Enable conversion operator using SFINAE

I am trying to overload operator T() with SFINAE to return a copy when T is a fundamental type, and a const reference when T is a class.

When using double in my example below, I cannot remove the second overload (using std::is_class ).

That is, I get a message:

 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; } 
+6
source share
3 answers

T already known at the time you instantiated your class member functions, so no replacement happens, and instead of SFINAE you get a tough error. The simplest workaround is to introduce a template template parameter for these operator overloads and its default value is T , so type inference 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

+9
source

Without solving the problem of why the wrong operator was not dropped to solve a specific problem at hand, that is , to return 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 the typedef type of a member, which is defined as T if B is true at compile time or 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; } 
+3
source

You should read the definition of std :: enable_if

template <bool B, class T = void> struct enable_if;

"If B is true, std :: enable_if is of type public type typedef equal to T, otherwise there is no typedef member."

-2
source

Source: https://habr.com/ru/post/979472/


All Articles