c++ - 具有多个枚举的C++运行时类型切换

标签 c++ templates variadic-templates

这是一个魔术开关问题,解决方案描述为here。但是,我想知道是否有可能使它成为3维的,即让它基于三个给定的枚举进行切换。在理想情况下,当然首选n维。我首先尝试使其变为二维,如下所示,但遇到了两个可变参数解压缩问题,但我无法确定它是如何工作的。

template<class Enum, class Enum2, template<Enum, Enum2>class Z>
struct magic_switch {
  // return value of a call to magic_switch(Args...)
  template<class...Args>
  using R = std::result_of_t<Z<Enum(0), Enum2(0)>(Args...)>;
  // A function pointer for a jump table:
  template<class...Args>
  using F = R<Args...>(*)(Args&&...);
  // Produces a single function pointer for index I and args Args...
  template<size_t I, size_t I2, class...Args>
  F<Args...> f() const {
    using ret = R<Args...>;
    return +[](Args&&...args)->ret{
      using Invoke=Z<Enum(I), Enum(I2)>;
      return Invoke{}(std::forward<Args>(args)...);
    };
  }
  // builds a jump table:
  template<class...Args, size_t...Is, size_t ...Is2>
  std::array<F<Args...>,size_t(Enum::COUNT)>
  table( std::index_sequence<Is...>, std::index_sequence<Is2...> ) const {
    return {{
      f<Is, Is2, Args...>()... ... // << -- 2d expansion not working
    }};
  }
  template<class...Args>
  R<Args...> operator()(Enum n, Enum2 n2, Args&&...args) {
    // a static jump table for this case of Args...:
    static auto jump=table<Args...>(std::make_index_sequence<size_t(Enum::COUNT)>{}, std::make_index_sequence<size_t(Enum2::COUNT)>{});
    // Look up the nth entry in the jump table, and invoke it:
    return jump[size_t(n) + size_t(Enum::COUNT) * size_t(n2)](std::forward<Args>(args)...);
  }
};

调用此代码如下

enum class abc_enum { a, b, c, COUNT };
enum class defg_enum { d, e, f, g, COUNT };

template<abc_enum e, defg_enum f>
struct stuff {
  void operator()() const {
    std::cout << (int)e << '\n';
    std::cout << (int)f << '\n';
  }
};
magic_switch<abc_enum, defg_enum, stuff>{}(abc_enum::b, defg_enum::f);

但是,由于双重可变包扩展,以上内容无法编译。对于更大的尺寸,甚至必须拆开更多的可变包装。 n维魔术开关问题有解决方案吗?

最佳答案

您可以逐步进行,

首先将每个运行时枚举转换为可能的std::variantstd::integral_constant:

template <typename Enum, typename Seq> struct EnumVariantHelper;

template <typename Enum, std::size_t ... Is>
struct EnumVariantHelper<Enum, std::index_sequence<Is...>>
{
    using type = std::variant<std::integral_constant<Enum, Enum(Is)>...>;
};

template <typename Enum, std::size_t Count>
using EnumVariant = typename EnumVariantHelper<Enum, std::make_index_sequence<Count>>::type;

template <typename Enum, std::size_t Count>
struct AsVariant
{
    template <Enum E>
    struct F
    {
        EnumVariant<Enum, Count> operator()() const
        {
            return std::integral_constant<Enum, E>{};
        }
    };
};

然后,将组合 Material 放入std::visit,您可以执行以下操作:
auto v1 = magic_switch<abc_enum, abc_enum::COUNT,
                       AsVariant<abc_enum, std::size_t(abc_enum::COUNT)>::F>{}(abc_enum::b);
auto v2 = magic_switch<defg_enum, defg_enum::COUNT,
                       AsVariant<defg_enum, std::size_t(defg_enum::COUNT)>::F>{}(defg_enum::f);

std::visit([](auto e1, auto e2){ return stuff<e1(), e2()>{}(); }, v1, v2);

Demo

关于c++ - 具有多个枚举的C++运行时类型切换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60276740/

相关文章:

c++ - psd文件格式

c++ - 如何使用多个 SVM 分类器 - 每个分类器都有一个特定的内核 - 作为 "one vs rest classification"方案?

c++ - Sizeof 在模板中失败,即使类型都已定义

c++ - 两个带参数包的函数的重载解析

c++ - Concepts-Lite 将如何与可变参数模板交互?

c++ - 使用 MYSQL 服务器 (mingw32-make) 为 QT 构建驱动程序时出错

C++ fstream 正在写十六进制而不是字符串?

c++ - C++ 中的函数对象自动检测类型

c++ - 具有 lambda 函数参数的重载模板函数的语法

c++ - 创建一个编译时键到类型映射,通过调用可变参数函数来填充