I am creating a state machine with the Boost::Ext SML library. I have a number of states (A, B, C, D...) and in most cases, states will transition to another subject to common events. For instance, if in state A or B or C and the event "GoToD" is processed, the state will transition to D. To my knowledge, there is no way to encode this commonality using the aforementioned library, and as my number of states increases, my transition table becomes very large and fragile. It's already looking something like this:
struct MyStateMachine {
auto operator()() const noexcept {
return sml::make_transition_table(
*sml::state<A> + sml::event<GoToB> = sml::state<B>,
sml::state<A> + sml::event<GoToC> = sml::state<C>,
sml::state<A> + sml::event<GoToD> = sml::state<D>,
sml::state<B> + sml::event<GoToA> = sml::state<A>,
sml::state<B> + sml::event<GoToC> = sml::state<C>,
sml::state<B> + sml::event<GoToD> = sml::state<D>,
sml::state<C> + sml::event<GoToA> = sml::state<A>,
sml::state<C> + sml::event<GoToB> = sml::state<B>,
sml::state<C> + sml::event<GoToD> = sml::state<D>,
sml::state<D> + sml::event<GoToA> = sml::state<A>,
sml::state<D> + sml::event<GoToB> = sml::state<B>,
sml::state<D> + sml::event<GoToC> = sml::state<C>,
}
};
There are nuances I've omitted above (there are some guards on common transitions, for instance), but this gets to the root of the issue I'm encoutering. I'm wondering if there is either a programatic way to commonize these transitions, or a better way of thinking about the fundamental design of this state machine.
I have tried writing helper functions (see below) to encode common transitions, but I'm not sure how to do so such that they can be amalgamated into a single transition table using this library. I've also considered using pre-processor macros, but I don't like that solution.
template <typename From>
auto make_common_transitions() {
return sml::make_transition_table(sml::state<From> + sml::event<GoToA> = sml::state<A>,
sml::state<From> + sml::event<GoToB> = sml::state<B>,
sml::state<From> + sml::event<GoToC> = sml::state<C>,
sml::state<From> + sml::event<GoToD> = sml::state<D>);
}