Search code examples
c++templatesboostboost-mpl

How to enable a constructor with mpl techniques


I am little stuck with boost::enable_if and how to make a constructor switch with it.

The code is this:

struct NullType{};
struct TestType{};
struct NonNull{};

template<typename T, typename U = NullType>
struct TemplateStruct
{
    TemplateStruct(int i, typename boost::enable_if<boost::is_same<U, NullType>, void* >::type dummy = 0)
    {
        std::cout << "One Param == " << i << std::endl;
    }

    TemplateStruct(int i, int j, typename boost::disable_if<boost::is_same<U, NullType>, void* >::type dummy = 0)
    {
        std::cout << "Two Param == " << i << "," << j << std::endl;
    }
};

int main(int /*argc*/, char**)
{
    TemplateStruct<TestType>(1);
    TemplateStruct<TestType,NonNull>(1,2);
    return 0;
}

What I want to archive is the following. It want that the first Ctor is only available when a NullType is given. In all other cases I want to disable the first Ctor and enable the second one.

At the moment I get a compile error because one of the constructors is invalid. But how can I make the Ctor a templated one and reuse the class template parameter?


Solution

  • This is one way to solve your problem as you want:

    template<typename T, typename U = NullType>
    struct TemplateStruct
    {
        TemplateStruct(int i)
        {
            boost::enable_if< boost::is_same<U,NullType>, void*>::type var = nullptr;
            std::cout << "One Param == " << i << std::endl;
        }
    
        TemplateStruct(int i, int j)
        {
            boost::disable_if< boost::is_same<U,NullType>, void*>::type var = nullptr;
            std::cout << "Two Param == " << i << "," << j << std::endl;
        }
    };
    
    int main()
    {
        TemplateStruct<TestType>(1);
        TemplateStruct<TestType,NonNull>(1,2);
        //will not compile TemplateStruct<TestType>(1,2);
        //will not compile TemplateStruct<TestType,NonNull>(1);
    }
    

    EDIT1: Or assuming your compiler of choice and the STL implementation you use supports static_assert and type traits (i.e. VS 2010 does) you can get better error messages if one tries to use the disabled ctor:

    template<typename T, typename U = NullType>
    struct TemplateStruct
    {
        TemplateStruct(int i)
        {
            static_assert( std::is_same<U,NullType>::value, "Cannot use one parameter ctor if U is NullType!" );
            std::cout << "One Param == " << i << std::endl;
        }
    
        TemplateStruct(int i, int j)
        {
            static_assert( !std::is_same<U,NullType>::value, "Cannot use two parameter ctor if U is not NullType!" );
            std::cout << "Two Param == " << i << "," << j << std::endl;
        }
    };
    

    EDIT2: Or if no is_same in your STL but you have static_assert:

    template<typename T, typename U = NullType>
    struct TemplateStruct
    {
        TemplateStruct(int i)
        {
            static_assert( boost::is_same<U,NullType>::value, "Cannot use one parameter ctor if U is NullType!" );
            std::cout << "One Param == " << i << std::endl;
        }
    
        TemplateStruct(int i, int j)
        {
            static_assert( !boost::is_same<U,NullType>::value, "Cannot use two parameter ctor if U is not NullType!" );
            std::cout << "Two Param == " << i << "," << j << std::endl;
        }
    };