Как включить конструктор с техникой mpl - PullRequest
4 голосов
/ 29 марта 2011

Я немного застрял с boost :: enable_if и как заставить конструктор переключаться с ним.

Код такой:

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

Я хочу заархивировать следующее. Он хочет, чтобы первый Ctor был доступен только тогда, когда указан NullType. Во всех остальных случаях я хочу отключить первый Ctor и включить второй.

В настоящий момент я получаю ошибку компиляции, потому что один из конструкторов недействителен. Но как я могу сделать Ctor шаблонным и повторно использовать параметр шаблона класса?

Ответы [ 3 ]

3 голосов
/ 29 марта 2011

Это один из способов решить вашу проблему так, как вы хотите:

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

РЕДАКТИРОВАТЬ1: или, если выбранный вами компилятор и используемая вами реализация STL поддерживают static_assert и traits type (то есть VS 2010 поддерживает), вы можете получить лучшие сообщения об ошибках, если попытаетесь использовать отключенный 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: или, если в вашем STL нет is_same, но у вас есть 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;
    }
};
1 голос
/ 29 марта 2011

Я не знаю решения вашей конкретной проблемы.

Возможно, этот код поможет (обратите внимание, что для этого вам не нужен механизм enable_if).По крайней мере, это может быть отправной точкой для лучшего решения:

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

Это не сработает, если специализация TemplateStruct <> нежелательна / невозможна или вы не хотите указывать NullType.

Что касается вашего беспокойства по поводу раздувания кода, я сомневаюсь, что оно уместно: в объектный код попадает только то, что было создано.

0 голосов
/ 29 марта 2011

Один из способов решить эту проблему - создать небольшую оболочку вокруг фактического класса и просто специализировать эту оболочку. Это хорошо работает, если вы не хотите включать / отключать несколько функций.

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