4

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

我要归档的内容如下。它希望第一个 Tor 仅在给定 NullType 时可用。在所有其他情况下,我想禁用第一个 Tor 并启用第二个。

目前我收到一个编译错误,因为其中一个构造函数无效。但是我怎样才能使 Ctor 成为模板化的并重用类模板参数呢?

4

3 回答 3

3

这是根据需要解决问题的一种方法:

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:或者假设您选择的编译器和您使用的 STL 实现支持 static_assert 和类型特征(即 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;
    }
};
于 2011-03-29T09:57:35.633 回答
1

我不知道您的确切问题的解决方案。

也许这段代码会有所帮助(请注意,您不需要 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,那将不起作用。

关于您对代码膨胀的担忧,我怀疑它是否相关:只有实例化的内容才能到达目标代码。

于 2011-03-29T09:04:32.020 回答
0

解决这个问题的一种方法是在实际类周围有一个小包装器,然后专门化那个包装器。如果您只想启用/禁用几个功能,这很有效。

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;
}
于 2011-03-29T10:01:20.893 回答