在枚举上构造类型并转发不同数量的参数

时间:2015-06-11 14:54:42

标签: c++ c++11 enums perfect-forwarding

我们说我有几种类型绑定到变体中。 另一方面,我有一个枚举,其中可以推导出一些以前的类型,所以我可以有一个运行时伪工厂:

#include <boost/variant.hpp>

enum class Type { W, X, Y, Z };

struct A {};

struct B
{
    B(int) {}
};

struct C
{
    C(int, int) {}
};

using variant_t = boost::variant<A, B, C>;

template<typename... Args>
variant_t MakeVariantOverEnum(Type type, Args&&... args)
{
    switch (type)
    {
        case Type::X: return B(std::forward<Args>(args)...); break;
        case Type::Z: return C(std::forward<Args>(args)...); break;            
        default:      return A(std::forward<Args>(args)...); break;
    }
}

// meant to be fully runtime
const Type GetTypeFromIO() { return Type::Z; }
const int GetFirstArgFromIO() { return 0; }
const int GetSecondArgFromIO() { return 0; }

int main()
{
    const Type type = GetTypeFromIO();
    const int firstArg = GetFirstArgFromIO();
    const int secondArg = GetSecondArgFromIO();    

    variant_t newVariant;

    if (firstArg != 0 && secondArg != 0) newVariant = MakeVariantOverEnum(type, firstArg, secondArg);
    else if (firstArg != 0)              newVariant = MakeVariantOverEnum(type, firstArg);
    else                                 newVariant = MakeVariantOverEnum(type);
}
在这段代码中,有两件事让我很烦恼:

**如何通过传递所有参数,然后丢弃那些无效的&#39;来对MakeVariantOverEnum进行1次调用?案例(我的样本中= = 0)?我可以使用一些SFINAE机制在MakeVariantOverEnum中进行吗?

**它没有编译,因为编译器试图将所有构造函数与所有参数匹配:

main.cpp: In instantiation of 'variant_t MakeVariantOverEnum(Type, Args&& ...) [with Args = {const int&, const int&}; variant_t = boost::variant<A, B, C>]':
main.cpp:44:100:   required from here
main.cpp:24:59: error: no matching function for call to 'B::B(const int&, const int&)'
         case Type::X: return B(std::forward<Args>(args)...); break;
                                                           ^
main.cpp:24:59: note: candidates are:
main.cpp:9:2: note: B::B(int)
  B(int) {}
  ^
main.cpp:9:2: note:   candidate expects 1 argument, 2 provided
main.cpp:7:8: note: constexpr B::B(const B&)
 struct B
        ^
main.cpp:7:8: note:   candidate expects 1 argument, 2 provided
main.cpp:7:8: note: constexpr B::B(B&&)
main.cpp:7:8: note:   candidate expects 1 argument, 2 provided

等等其他类型...

所以我的问题是:我怎么能让它在这一点上起作用?

谢谢!

PS:代码在这里生效=&gt; http://coliru.stacked-crooked.com/a/4bc1e326be27b3dd

1 个答案:

答案 0 :(得分:0)

解决问题的最简单方法:

enum class Type { W, X, Y, Z };

struct A {};

struct B
{
    B(int) {}
};

struct C
{
    C(int, int) {}
};

using variant_t = boost::variant<A, B, C>;

variant_t MakeVariantOverEnum(Type type, int param1, int param2)
{
    switch (type)
    {
        case Type::X: return B(param1); 
        case Type::Z: return C(param1, param2);             
        default:      return A();
    }
}

// meant to be fully runtime
const Type GetTypeFromIO() { return Type::Z; }
const int GetFirstArgFromIO() { return 0; }
const int GetSecondArgFromIO() { return 0; }

int main()
{
    const Type type = GetTypeFromIO();
    const int firstArg = GetFirstArgFromIO();
    const int secondArg = GetSecondArgFromIO();    

    variant_t newVariant = MakeVariantOverEnum(type, firstArg, secondArg);
}

可变参数模板只会让事情变得更复杂,无论如何都无法帮助你。

如果所有结构使用相同的参数(至少:如果使用该参数,则在任何地方使用相同的类型),这将起作用。但是,如果您为不同的对象使用不同的参数类型,则需要考虑在主函数本身中进行切换是否更容易(然后获取正确的参数):

假设以下扩展:

struct D
{
    D(float) {}
}

所以现在你突然有一种情况,你的const int firstArg将是一个浮动......(然而这对于B和C不起作用)

或者,您可以指定第三个参数float param3,并在创建类型时仅使用此参数。 (但那么param1和param2呢?)

注意:仍然可以使用一些工厂模式,但这会更复杂(每个对象都需要自己的工厂,它将获得正确的参数,然后创建正确的结构......)