Enable_if: minimum example for void member function with no arguments

I am trying to better understand std::enable_if in C ++ 11 and trying to write a minimal example: class A with a member function void foo() , which has different implementations based on the type T from the class template.
The following code gives the desired result, but I still do not understand it completely. Why does version V2 , but not V1 ? Why is a "redundant" type U needed?

 #include <iostream> #include <type_traits> template <typename T> class A { public: A(T x) : a_(x) {} // Enable this function if T == int /* V1 */ // template < typename std::enable_if<std::is_same<T,int>::value,int>::type = 0> /* V2 */ template <typename U=T, typename std::enable_if<std::is_same<U,int>::value,int>::type = 0> void foo() { std::cout << "\nINT: " << a_ << "\n"; } // Enable this function if T == double template <typename U=T, typename std::enable_if<std::is_same<U,double>::value,int>::type = 0> void foo() { std::cout << "\nDOUBLE: " << a_ << "\n"; } private: T a_; }; int main() { A<int> aInt(1); aInt.foo(); A<double> aDouble(3.14); aDouble.foo(); return 0; } 

Is there a better way to achieve the desired result, that is, to implement various implementations of the void foo() function based on the class template parameter?

+5
source share
2 answers

I know this will not fully answer your question, but it may give you some more ideas and insights on how you can use std::enable_if .

You can replace your foo member functions with the following and have identical functionality:

 template<typename U=T> typename std::enable_if<std::is_same<U,int>::value>::type foo(){ /* enabled when T is type int */ } template<typename U=T> typename std::enable_if<std::is_same<U,double>::value>::type foo(){ /* enabled when T is type double */ } 

While I got a pretty good idea of ​​how the enable_if function works, but unfortunately, I forgot most of my subtleties and just remember the more practical ways to use it.

+2
source

Regarding the first question: why does V1 not work? SFINAE only applies when overload resolution is enabled - V1, however, causes an error at the point where A is created, long before foo() resolves the overload.

I assume that there are many possible implementations, which, most correctly, depends on the specific case. A general approach would be to defer part A , which is different for different types of templates for a helper class.

 template <typename T> class A_Helper; template <> class A_Helper<int> { public: static void foo( int value ){ std::cout << "INT: " << value << std::endl; } }; template <> class A_Helper<double> { public: static void foo( double value ){ std::cout << "DOUBLE: " << value << std::endl; } }; template <typename T> class A { public: A( T a ) : a_(a) {} void foo(){ A_Helper<T>::foo(a_); } private: T a_; }; 

The rest of A can only be declared once in the general way - only parts that are different are deferred until assistant. Depending on your requirements, there are many possible options ...

0
source

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


All Articles