I have no idea which rules must be considered to use SFINAE to method overloading. I run multiple times in problems because there seams to be more rules involved as I know. So I hope that there is a set of rules which can be explained in short to help to solve the problems in general instead of asking questions again and again.
My start point was here: Specializing class with SFINAE if a parameter pack is needed
Code 1
class AA { public: using TRAIT = int; };
class BB { public: using TRAIT = float; };
template < typename T>
class Y
{
public:
template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
Y( ) { std::cout << "First" << std::endl; }
template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( ) { std::cout << "Second" << std::endl; }
};
error: 'template template Y::Y()' cannot be overloaded
To this problem I got a comment:
"the "constructor cannot be overloaded" problem can be solved by adding a dummy and defaulted template parameter (like , typename Z = void) to one of the constructors"
OK, changing my code to:
Code 2
template < typename T>
class Y
{
public:
template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type, typename X=int>
Y( X* = nullptr) { std::cout << "First" << std::endl; }
template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( ) { std::cout << "Second" << std::endl; }
};
OK, it compiles. But simplifying seams to works also which makes me doubtful.
Code 3
template < typename T>
class Y
{
public:
template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
Y( int* = nullptr) { std::cout << "First" << std::endl; }
template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( ) { std::cout << "Second" << std::endl; }
};
The last example works also! It has a default parameter in ONE of the constructors, but this parameter is not a templated one.
For me it is now quite unclear which rules are working behind to get the things to run here.
My first misunderstanding is, that I thought that SFINAE takes place by instantiating the constructor template and only one constructor becomes available. This is not the truth! Each parameter set for all constructors must be different!? Why? And in addition, why it should or must be a templated parameter? My example 3 seams to work but others gave me the advice to use a dummy and defaulted template parameter (like , typename Z = void)
. Can someone give me a bit background information on this topic?