开发者

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, ty开发者_如何学JAVApename 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?


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;
    }
};


I don't know solution to your exact problem.

Maybe this code would help (notice that you don't need enable_if machinery for that). At least it could be starting point for nicer solution:

#include <iostream>

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

template<typename T, typename U>
struct TemplateStruct
{  
    TemplateStruct(int i, int j)
    {
        std::cout << "Two Param == " << i << "," << j << std::endl;
    }
};

template<typename T>
struct TemplateStruct<T, NullType>
{
    TemplateStruct(int i)
    {
        std::cout << "One Param == " << i << std::endl;
    }
};

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

That won't work if specializing TemplateStruct<> is undesirable/impossible or you don't want to specify NullType.

Regarding your concern about code bloat, I doubt it is relevant: only what was instantiated gets to object code.


One way to solve this, is to have a small wrapper around the actual class and just specialize that wrapper. This works well if you only wan't to enable/disable a couple of functions.

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

template<typename T, typename U>
struct TemplateStruct
{
    TemplateStruct(int i){
        std::cout << "One Param == " << i << std::endl;
    }

    TemplateStruct(int i, int j){
        std::cout << "Two Param == " << i << "," << j << std::endl;
    }

    void FunctionToDisableFor1Param(){
    }

    void FunctionToAlwaysEnable(){
    }
};

template<class T, class U = NullType>
struct TSWrapper : public TemplateStruct<T,U>{
    typedef TemplateStruct<T,U> BaseType;

    TSWrapper(int i, int j)
        : BaseType(i,j)
    {}
};

template<class T>
struct TSWrapper<T,NullType> : public TemplateStruct<T,NullType>{
    typedef TemplateStruct<T,NullType> BaseType;

    TSWrapper(int i)
        : BaseType(i)
    {}

private:
    using BaseType::FunctionToDisableFor1Param;
};

int main()
{
    TSWrapper<TestType> x(1);
    TSWrapper<TestType,NonNull> y(1,2);
    x.FunctionToAlwaysEnable();
    y.FunctionToDisableFor1Param();
    // uncomment for compile time error
    //x.FunctionToDisableFor1Param();
    return 0;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜