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

Construct type over enum and forward different number of arguments

本文关键字:参数 转发 枚举 类型      更新时间:2023-10-16

假设我有几个类型绑定到一个变体中。另一方面,我有一个枚举,可以从中推断出一些以前的类型,所以我可以有一个运行时伪工厂:

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

在此代码中困扰我的两件事:

** 如何通过传递所有参数然后丢弃那些"无效"情况(在我的示例中 ==0)来只调用 1 次 MakeVariantOverEnum?我可以在MakeVariantOverEnum中使用一些SFINAE机制来做到这一点吗?

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

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:代码在这里直播=> http://coliru.stacked-crooked.com/a/4bc1e326be27b3dd

最简单的问题方法:

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

可变参数模板只会使事情变得更加复杂,不会以任何方式帮助您。

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

假设以下扩展:

struct D
{
    D(float) {}
}

所以现在你突然有一个情况,你的const int firstArg会是一个漂浮物......(但是,这对 B 和 C 不起作用)

或者,您可以指定第三个参数float param3并且仅在创建类型时使用此参数。(但是参数1和参数2呢?

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