C++11/g++ 4.8 update
If anybody is interested, inherited constructors from C++11 are a real game changer for the solution exposed here. I have just upgraded from g++ 4.6 and to 4.8, that has better support for C++11. I am so happy I did!
I am able to change the ugly
explicit LevelState(Machine &m, StateRef<LevelState> &state) :
GenericState<Machine, LevelState>(m, state) {}
into the neat
using GenericState::GenericState;
Since a state machine can contain many abstract and concrete states, that makes the whole code much more readable.
The code below reflects this change.
Introduction
The code belowThis finds its origin in the following reflection.
In their book from 1995, the so-called gang of four (GoF) described the state pattern. What they were actually telling us in their description, is that any object oriented language that implements dynamic polymorphism has an embedded finite state machine (FSM) engine. C++ is such a language, and the example code in the book is written in that language. Why then, do we have to use large frameworks, libraries and tools in order to implement state machines in C++?
Not so neat. I started to wonder if templates couldn't help me to parametrize the target state in ChangeState()ChangeState()
. If the state had both a reference to the FSM and the ability to transform itself as a result of a transition, surely I would get a much simpler and cleaner syntax.
As the code below testifies (public domain, use it as you wish, but don't blame me - compiles with g++ 4.6, C++11 switched on), I have managed to implement the state machine depicted above, in such a simple syntax, with the help of a 40-line state template that I have called GenericStateGenericState
(genericstate.h, the rest is the state machine code):
- Entry and exit actions can be defined at any state level. Transition actions are programmed as regular instructions in the event handlers before the actual state transitions. There is, however, a difference with the UML in the order of execution: transition actions, exit actions (old state), entry actions (new state). The UML has exit, transition actions, entry. But mine is the same order as Miro Samek's model (http://www.state-machine.com/) - i.e. it is not uncommon and there is nothing wrong with it as long as it is consistent.
- Guards are regular "if" or "switch" statements in event handlers.
- Event parameters are regular event handler arguments. The event handler signature is free (and clutter-free).
- Composite states are implemented by applying the same model recursively. In the sate machine above, the state "Left" contains a "ColorState"
ColorState
virtual state that can be "Red" or "Blue". However, when going from "Left" to "Right", the exit action from the current color will not be executed (contrary to the UML semantics, but not a practical problem I believe). - Orthogonal states are managed by letting the FSM have several virtual state members instead of just one ("LevelState"
LevelState
and "DirectionState"DirectionState
in "Machine"Machine
in the example). - Access to the FSM members is given to all states through the FSM reference "m" (e.g. m.changedColor()
m.changedColor()
).
Please commentQuestions:
Output from the program
entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color
entering High changed color leaving High entering Low already Low leaving Low entering High already High unhandled event changed color unhandled event changed color