Klaus
Klaus

Reputation: 25603

enabling a constructor with sfinae if given template argument provides a type definition

I want to enable one and only one of two constructors in a template class depending if the given type as template parameter defines a type or not.

Here I want to add the defined type from the given template as additional parameter in the constructor and forward this parameter if it is present. But see:

class A
{  // this class did not provide ConstructorParms type definition
    public:
        A( int i) {}
};

class B
{  // this class provide the type ConstructorParms
    public:
        using ConstructorParms= double;

        B( double d, int i) {}
};


template <typename T>
class Check: public T
{
    public:
        // ??? enable_if T has typename T::ConstructorParms
        Check( typename T::ConstructorParms parms, int i): T( parms, i) {}

        // ??? enable_if T has NOT typename T::ConstructorParms
        Check( int i): T(i){}
};

int main()
{
    Check<A> ca(9);             
    Check<B> cb(1.23, 10);
    return 0;
}

I run into trouble, because the constructor "method" itself has no template parm. Any idea?

Attention ( cause of given answer ): The code fragment is really simplified. Forwarding to the parent constructor with using is not an option, because the real world class Check needs some parameters for them self. This makes forwarding to the parent constructor not possible.

Upvotes: 0

Views: 222

Answers (1)

Columbo
Columbo

Reputation: 60979

You could solve this using SFINAE, but there is a much easier solution since C++11: Inheriting constructors.

template <typename T>
class Check: public T
{
    public:
        using T::T;
};

In case the constructor does more than only forwarding; use this general solution:

#include <type_traits>

template< typename T >
struct HasCtorParamTypedef
{
    template< typename U,
              typename = typename U::ConstructorParms >
    static int f( U );

    static void f( ... );

    static const bool value = std::is_same<decltype(f(std::declval<T>())), int>::value;
};

template <typename T>
struct Check: public T
{
        // Is only enabled if T does have the typedef
        template <typename U = T,
                  typename = typename std::enable_if<HasCtorParamTypedef<U>::value>::type >
        Check( typename U::ConstructorParms parms, int i): T( parms, i) {}

        // Is only enabled if T does **not** have the typedef
        template <typename U = T,
                  typename = typename std::enable_if<!HasCtorParamTypedef<U>::value>::type >
        Check( int i ): T(i){}
};

Upvotes: 2

Related Questions