从样板代码到模板实现

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)为某些模板构造,其中可以简化所有样板代码,以防我在开发过程中添加新状态。

唯一的限制是:

  1. 使用 C++17 或更低版本(抱歉,请不要使用 c++20 的奇特功能)。

  2. 不要更改接口(不建议按类型等方式访问)。

pao*_*olo 5

如果您只想避免添加另一行,例如

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)

  • 不,但是[你的想法的这个版本确实](https://godbolt.org/z/jf9qjK1fq)。非常好的解决方案。+1 (2认同)