这是一个魔术开关问题,解决方案描述为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::variant
的std::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/