// Written by Alexander Nasonov alnsn@yandex.ru #include #include #include #include #include #include #include #include #include #include #include #include #include template struct add_transition { typedef void (*transition_fn)(Fsm&, Event); transition_fn* m_transitions; add_transition(transition_fn* transitions) : m_transitions(transitions) {} template void operator()(State*) const { typedef typename Fsm::states states; typedef typename boost::mpl::begin::type begin; typedef typename boost::mpl::end::type end; typedef typename boost::mpl::find::type iter; typedef typename boost::mpl::distance::type index; BOOST_STATIC_ASSERT(( !boost::is_same::value )); m_transitions[index::value] = &add_transition::do_transition; } template static void do_transition(Fsm& fsm, Event event) { fsm.m_states = fsm(boost::get(fsm.m_states), event); } }; template struct fsm_dispatcher { typedef typename Fsm::states states; typedef typename boost::mpl::size::type state_count; typedef void (*transition_fn)(Fsm&, Event); transition_fn m_transitions[state_count::value]; fsm_dispatcher() { using boost::mpl::_1; add_transition adder(m_transitions); boost::mpl::for_each >(adder); } void operator()(Fsm& fsm, Event event) const { m_transitions[fsm.m_states.which()](fsm, event); } }; struct Active {}; struct Stopped : Active {}; struct Running : Active {}; struct EvStartStop {}; struct EvReset {}; struct Fsm { typedef boost::mpl::vector states; typedef boost::make_variant_over::type state_variant; state_variant m_states; template Fsm(InitialState state) : m_states(state) {} Stopped operator()( Running, EvStartStop ) { std::cout << "Running --> (EvStartStop) --> Stopped\n"; return Stopped(); } Running operator()( Stopped, EvStartStop ) { std::cout << "Stopped --> (EvStartStop) --> Running\n"; return Running(); } Stopped operator()( Active, EvReset ) { std::cout << "Active --> (EvReset) --> Stopped\n"; return Stopped(); } template void process_event(Event event) { static fsm_dispatcher d; d(*this, event); } }; int main() { Stopped initial; EvReset evReset; EvStartStop evStartStop; Fsm fsm(initial); fsm.process_event(evStartStop); fsm.process_event(evReset); fsm.process_event(evStartStop); fsm.process_event(evStartStop); fsm.process_event(evReset); }