coding challenges · advanced
State Machine with std::variant
Microsoft state machine via std::variant. Model each state as its own struct (Idle, Active{job}, Fault{reason}) and the state as variant<Idle,Active,Fault> — state-specific data travels with the state, and invalid (state,data) combinations are unrepresentable. std::visit with the 'overloaded' lambda idiom acts on the current state and the compiler enforces exhaustiveness (forgetting an alternative is a compile error). Transitions are overloaded on(State,Event)->State functions plus a variadic catch-all that ignores invalid events; dispatch() std::visits to pick the overload and assigns the returned next state. The machine always holds exactly one valid state. It's O(1) and heap-free (states inline, sized to the largest alternative). Use enum+switch for trivial FSMs, the GoF State pattern (virtual classes) when states are open/extensible, or a table-driven FSM for large state spaces.
State machine with std::variant: each state is its own type (its data travels with it), illegal states are unrepresentable, and std::visit + the overloaded idiom forces exhaustive handling (compile error if you miss one). Transitions = on(State,Event)->State overloads + a catch-all; dispatch = visit then assign. O(1), heap-free; use the GoF State pattern instead when states are open/extensible.
The code
// State machine with std::variant — each state is its own TYPE,// transitions return the next state. No enum, no switch, no invalid states.struct Idle {};struct Active { int job; };struct Fault { std::string reason; };
using State = std::variant<Idle, Active, Fault>;
// Eventsstruct Start { int job; };struct Trip { std::string why; };struct Reset {};
// Transition table = overloaded visitor on (state, event).struct Machine { State on(Idle, Start e) { return Active{e.job}; } State on(Active, Trip e) { return Fault{e.why}; } State on(Fault, Reset) { return Idle{}; } template<class S, class E> State on(S s, E) { return s; } // ignore others
template<class E> void dispatch(State& st, E ev) { st = std::visit([&](auto s){ return on(s, ev); }, st); }};
// Act on the CURRENT state with a visitor (overload set):void run(const State& st) { std::visit(overloaded{ [](Idle) { /* sleep */ }, [](const Active& a){ work(a.job); }, [](const Fault& f){ alarm(f.reason); }, }, st);}What this lesson walks through
- 01Each state is its own TYPE (variant, not enum)
- 02std::visit + overloaded — act on the current state
- 03Transitions = on(state, event) → next state
- 04Run it — and invalid events are safely ignored
- 05Trade-offs — variant vs the State pattern
Model the state as variant<Idle, Active, Fault>. Each state is a struct carrying exactly its own data — Active has a job, Fault has a reason. An enum would pile that data into one shared struct where most fields are invalid; variant makes illegal states unrepresentable.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of State Machine with std::variant and 100+ animated C++ interview lessons.