Pab*_*blo 2 c++ templates stdtuple c++17
我正在实现一个有限状态机,其中所有可能的状态都存储在std::tuple.
这是我面临的问题的最小编译示例及其 godbolt 链接https://godbolt.org/z/7ToKc3T3W:
#include <tuple>
#include <stdio.h>
struct state1 {};
struct state2 {};
struct state3 {};
struct state4 {};
std::tuple<state1, state2, state3, state4> states;
template<size_t Index>
void transit_to()
{
auto state = std::get<Index>(states);
//Do some other actions over state....
}
void transit_to(size_t index)
{
if (index == 0) return transit_to<0>();
if (index == 1) return transit_to<1>();
if (index == 2) return transit_to<2>();
if (index == 3) return transit_to<3>();
}
int main()
{
for(int i=0; i<=3; ++i)
transit_to(i);
}
Run Code Online (Sandbox Code Playgroud)
就我而言,我想将实现更改void transit_to(size_t index)为某些模板构造,其中可以简化所有样板代码,以防我在开发过程中添加新状态。
唯一的限制是:
使用 C++17 或更低版本(抱歉,请不要使用 c++20 的奇特功能)。
不要更改接口(不建议按类型等方式访问)。
如果您只想避免添加另一行,例如
if (index == 4) return transit_to<4>();
Run Code Online (Sandbox Code Playgroud)
当你添加一个新的状态,例如struct state5,你可以transit_to(std::size_t)像这样实现:
// Helper function: Change state if I == idx.
// Return true, if the state was changed.
template <std::size_t I>
bool transit_if_idx(std::size_t idx) {
bool ok{false};
if (idx == I) {
transit_to<I>();
ok = true;
}
return ok;
}
template <std::size_t... Is>
bool transit_to_impl(std::size_t idx, std::index_sequence<Is...>) {
return (transit_if_idx<Is>(idx) || ...);
}
void transit_to(std::size_t index) {
constexpr static auto tupleSize = std::tuple_size_v<decltype(states)>;
[[maybe_unused]] auto const indexValid =
transit_to_impl(index, std::make_index_sequence<tupleSize>{});
assert(indexValid); // Check if index actually referred to a valid state
}
Run Code Online (Sandbox Code Playgroud)