C++ C++;模板元编程嵌套开关语句

C++ C++;模板元编程嵌套开关语句,c++,template-meta-programming,C++,Template Meta Programming,让我们假设我有一个像这样的联合类型(变体类型)(为了演示而简化) 我打算将这个值分配给不同的函数,比如(实际上是函数对象,但再次简化…) 对于使用2个参数调用函子的情况。但对于3个参数的情况,情况变得更糟 有没有办法通过元编程来概括它?理想情况下,我只有一个switch语句,并生成所有嵌套语句。您可以创建一个可变模板函数,该函数对第一个参数执行切换,并使用其余参数和保存第一个参数类型的lambda调用自身: template<typename F, typename... T> //

让我们假设我有一个像这样的联合类型(变体类型)(为了演示而简化)

我打算将这个值分配给不同的函数,比如(实际上是函数对象,但再次简化…)

对于使用2个参数调用函子的情况。但对于3个参数的情况,情况变得更糟


有没有办法通过元编程来概括它?理想情况下,我只有一个switch语句,并生成所有嵌套语句。

您可以创建一个可变模板函数,该函数对第一个参数执行
切换,并使用其余参数和保存第一个参数类型的lambda调用自身:

template<typename F, typename... T>
// decltype(auto) is used to deduce the return type from F, throughout
decltype(auto) apply_func(F f, const Value& v, T&&... vs) { // can't say "any number of arguments, all Values", so say "any arguments of any type" and just convert them to Value later
    switch (v.dtype) {
    case Type::Int64: // bind first argument of f to chosen variant of v, then apply new function (with one less argument) to remaining Values
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.i, args...);
            }, std::forward<T>(vs)...
        );
    case Type::UInt64:
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.u, args...);
            }, std::forward<T>(vs)...
        );
    case Type::Double:
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.d, args...);
            }, std::forward<T>(vs)...
        );
    default: throw std::invalid_argument("Unknown dtype");
    }
}

// final overload, when all arguments have been switched on and the chosen variants have been saved into f
template<typename F>
decltype(auto) apply_func(F f) {
    return f();
}
模板
//decltype(auto)用于从F推断返回类型
decltype(auto)apply_func(F F,const Value&v,T&&…vs){//不能说“任何数量的参数,所有值”,所以说“任何类型的任何参数”,然后将它们转换为值
开关(v.dtype){
case Type::Int64://将f的第一个参数绑定到所选的v变量,然后将新函数(少一个参数)应用到其余值
返回应用函数(
[&](常量自动&…参数)->decltype(自动){
返回f(v.i,args…);
},标准::正向(vs)。。。
);
案例类型::UInt64:
返回应用函数(
[&](常量自动&…参数)->decltype(自动){
返回f(v.u,参数…);
},标准::正向(vs)。。。
);
案例类型::双:
返回应用函数(
[&](常量自动&…参数)->decltype(自动){
返回f(v.d,参数…);
},标准::正向(vs)。。。
);
默认值:throw std::无效的_参数(“未知数据类型”);
}
}
//最终重载,当所有参数都已打开且所选变量已保存到f中时
模板
decltype(自动)应用函数(F){
返回f();
}

你把这个例子简化得太多了。e、 g.
类型是什么?现在,你可能会发现
std::variant
std::visit
很方便。不会使您的问题完全消失,但至少提供了一种机制来更干净地实现您的代码(并且可能没有实际的案例说明)。这恰好是
std::visit
使用
std::variant
所能做到的。所显示的代码基本上是重新发明了
std::variant
轮子。感谢您指出关于
std::visit
,我不能使用
std::variant
,但是,也许看看
std::visit
的实现会给我一些关于如何实现的提示。
std::visit
是基于可变模板参数的工作方式,而
std::variant
是基于可变模板参数的<代码>std::visit
的实现对您没有多大帮助,除非您还使用带有可变参数的模板来组成您的联合。如果您这样做,您还可以使用
std::variant
。谢谢!非常接近我想要实现的。我可以以此为基础来解决问题。
template<typename... T> auto eval(const T&... t)
{
   // ...
}
template<typename T1, typename T2> auto sum(const T1& a, const T2& b)
{
   return a+b;
}
  switch (o1.dtype)
  {
    case Type::Int64:
      switch (o2.dtype)
      {
        case Type::Int64:
          F(o1.i, o2.i);
        case Type::Double:
          F(o2.i, o2.d);
        //...
      }
      break;
    case Type::Double
      //...
      
template<typename F, typename... T>
// decltype(auto) is used to deduce the return type from F, throughout
decltype(auto) apply_func(F f, const Value& v, T&&... vs) { // can't say "any number of arguments, all Values", so say "any arguments of any type" and just convert them to Value later
    switch (v.dtype) {
    case Type::Int64: // bind first argument of f to chosen variant of v, then apply new function (with one less argument) to remaining Values
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.i, args...);
            }, std::forward<T>(vs)...
        );
    case Type::UInt64:
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.u, args...);
            }, std::forward<T>(vs)...
        );
    case Type::Double:
        return apply_func(
            [&](const auto&... args) -> decltype(auto) {
                return f(v.d, args...);
            }, std::forward<T>(vs)...
        );
    default: throw std::invalid_argument("Unknown dtype");
    }
}

// final overload, when all arguments have been switched on and the chosen variants have been saved into f
template<typename F>
decltype(auto) apply_func(F f) {
    return f();
}