Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use std::enable_if to enable or disable constructors depending on template types?

I have the following templated object:

template< typename type_1, typename type_2 > struct result
{
    // I want to enable these two constructors only if type_1 != type_2
    result( type_1 f ) : foo{f} {}
    result( type_2 b ) : bar{b} {}

    // I want to enable this constructor only if type_1 == type_2
    result( type_1 f, type_2 b ) : foo{f}, bar{b} {}

    // Other member functions removed.

    type_1 foo;
    type_2 bar;
};

How do I use std::enable_if to enable or disable the constructors as required?

e.g:

This one would have only the first two constructors:

result<string,int> // type_1 != type_2

This one would have only the third constructor:

result<int,int> // type_1 == type_2
like image 393
x-x Avatar asked Oct 30 '14 02:10

x-x


2 Answers

This seems working, but I am not sure it is the optimal way

So just add new template parameters with default values to the constructor to enable SFINAE

#include <type_traits>

template< typename type_1, typename type_2 >
struct result
{
    // I want to enable these two constructors only if type_1 != type_2
    template<typename T1 = type_1, typename T2 = type_2>
    result( type_1 f, 
            typename std::enable_if<!std::is_same<T1, T2>::value>::type * = nullptr )
       : foo{f} {}
    template<typename T1 = type_1, typename T2 = type_2>
    result( type_2 b, 
           typename std::enable_if<!std::is_same<T1, T2>::value, int >::type * = nullptr )
       : bar{b} {}                                        /*     ^^^ need this to avoid duplicated signature error with above one*/ 

    // I want to enable this constructor only if type_1 == type_2
    template<typename T1 = type_1, typename T2 = type_2>
    result( type_1 f, type_2 b,
            typename std::enable_if<std::is_same<T1, T2>::value>::type * = nullptr ) 
       : foo{f}, bar{b} {}

    type_1 foo;
    type_2 bar;
};

int main()
{
   result<int, double> r(1);
   result<int, double> r2(1.0);

   result<int, int> r3(1, 2);

   // disbaled
   //result<int, double> r4(1, 2.0);
   //result<int, int> r5(1);
}

Also read: Select class constructor using enable_if

like image 136
Bryan Chen Avatar answered Oct 04 '22 02:10

Bryan Chen


The primary template can serve as a specialization for mistmatched types. For matching types you can partially specialize:

template <typename type_1, typename type_2>
struct result
{
    result( type_1 f ) : foo{f} {}
    result( type_2 b ) : bar{b} {}

    type_1 foo;
    type_2 bar;
};

template <typename type>
struct result<type, type>
{
    result( type f, type b ) : foo{f}, bar{b} {}

    type foo;
    type bar;
};
like image 21
David G Avatar answered Oct 04 '22 02:10

David G