FAQ

Limitations

on_entry<_> across translation units

When on_entry<_> (the wildcard entry handler) is defined in one translation unit while the initial-event specialization is left undefined, the linker reports an undefined reference. Make sure the entry handler is fully defined where it is used.

Dispatch priority: a specific on_entry<e1> handler takes priority over the on_entry<_> wildcard. The wildcard fires only when no specific handler matches the event used to enter the state.

// on_entry<e1> fires when entering via e1 (specific handler wins)
// on_entry<_>  fires when entering via any other event (no specific handler)

operator, with two raw member-function-pointer actions

Two raw member-function-pointer actions combined with the comma operator (&A::f, &A::g) select the built-in comma operator, because both operands are class types — so SML's action-sequencing is bypassed. Wrap the actions with wrap(...) to restore sequencing:

*"s1"_s + event<e> / (wrap(&A::f), wrap(&A::g)) = X

See example/actions_guards.cpp for a worked example.

Frequently asked questions

How do I get / inspect the current state(s)?

Use sm.is(...) to test the active state, or sm.visit_current_states(...) to iterate them. state.c_str() gives the state name:

assert(sm.is("idle"_s));
sm.visit_current_states([](auto state) { std::cout << state.c_str() << '\n'; });

How do I check whether the machine is in one of several states?

is(...) accepts one state per orthogonal region, so all regions are tested in a single call (no need to release a held mutex between checks):

sm.is(s1, s2);  // region 0 == s1 AND region 1 == s2

How do I know whether an event was handled? Can I pass an event instance?

process_event returns booltrue when the event was handled, false otherwise (an unhandled event triggers unexpected_event<E>). You can pass either a type or an instance:

const bool handled = sm.process_event(my_event{42});

How do I dispatch events from another thread or an async handler?

Configure the machine with a process_queue / defer_queue policy and call sm.flush_queue() to drain events that were pushed after process_event returned (for example from an asynchronous callback). flush_queue() is a no-op when empty.

How do I discard deferred events?

Use the sml::clear_defer action in a transition to drop events that were deferred earlier.

Is SML part of Boost?

[Boost].SML is a standalone, single-header library with no dependencies — neither STL nor Boost are required. It is part of the boost-ext project; it is not (currently) an official Boost library, and you do not need Boost to use it.

Is SML a Moore or a Mealy state machine?

Both. Transition actions run on transitions (Mealy), while on_entry<...> / on_exit<...> provide per-state actions (Moore).