Это проблема магического переключателя c, решение было описано здесь . Однако мне было интересно, можно ли сделать его трехмерным, т.е. позволить ему переключаться на основе трех заданных перечислений. В идеальном случае, n-мерный, конечно, предпочтительнее. Сначала я попытался сделать его двухмерным, как показано ниже, но я столкнулся с двойной вариацией c распаковки и не могу выяснить, как это будет работать.
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);
Однако вышеприведенное не компилируется из-за двойного расширения пакета c. Для большего размера, еще больше упаковок variadi c должно быть распаковано. Есть ли решение проблемы n-мерного переключателя magi c?