This is a variant of the solution posted here, without state creation/destruction penalty.
Note that my comment in the original question about the simplification provided by C++11's inherited constructors applies here too, but I have not updated the code in this question accordingly. That is left as an exercise to the reader.
The variant
I like the event/action syntax of the solution I proposed in my question. However, I really dislike the runtime penalty of creating/destroying states on the fly (I have made no measurement, but I dislike the principle).
I present hereafter a variant where the event/action syntax simplicity is pretty much kept (although slightly modified), but all states are created in advance. To keep my syntax, the states obviously need to be context-aware, which makes my solution anti-flyweight (one instance of every single concrete state per instance of a state machine). My feeling is that the cost in RAM is more affordable to the applications I have in mind than the runtime penalty. Another cost of this variant is a more complex declaration for states: declaration of state instances, need for a state to refer not only to the state machine but also to the nearest superstate.
Obviously, a straight application of the GoF's state pattern is an alternative for applications that need both flyweight and runtime efficiency (at the expense of event/action syntax simplicity).
Please comment on this.
genericstate.h
#ifndef GENERICSTATE_H
#define GENERICSTATE_H
template <typename StateMachine, class State, class SuperState = StateMachine>
class GenericState
{
public:
static void init(State *&state, State &initState) {
state = &initState;
initState.entry();
}
protected:
explicit GenericState(StateMachine &m, State *&state) :
m(m), s(m), state(state) {}
explicit GenericState(StateMachine &m, State *&state, SuperState &s) :
m(m), s(s), state(state) {}
void change(State &targetState) {
exit();
init(state, targetState);
}
private:
virtual void entry() {}
virtual void exit() {}
protected:
StateMachine &m;
SuperState &s;
private:
State *&state;
};
#endif // GENERICSTATE_H
machine.h
#ifndef MACHINE_H
#define MACHINE_H
#include <string>
#include <iostream>
#include "genericstate.h"
class Machine
{
public:
Machine() :
high(*this, levelState), low(*this, levelState),
left(*this, directionState), right(*this, directionState) {}
~Machine() {}
void start();
public:
enum Color {
BLUE,
RED
};
public:
void liftUp() { levelState->liftUp(); }
void bringDown() { levelState->bringDown(); }
void paint(Color color) { directionState->paint(color); }
void turnRight() { directionState->turnRight(); }
void turnLeft() { directionState->turnLeft(); }
private:
static void print(const std::string &str) { std::cout << str << std::endl; }
static void unhandledEvent() { print("unhandled event"); }
void changedColor() { print("changed color"); }
private:
class LevelState : public GenericState<Machine, LevelState> {
protected:
explicit LevelState(Machine &m, LevelState *&state) :
GenericState<Machine, LevelState>(m, state) {}
public:
virtual void liftUp() { unhandledEvent(); }
virtual void bringDown() { unhandledEvent(); }
} *levelState;
struct High : public LevelState {
explicit High(Machine &m, LevelState *&state) :
LevelState(m, state) {}
void entry() { print("entering High"); }
void liftUp() { print("already High"); }
void bringDown() { change(s.low); }
void exit() { print("leaving High"); }
} high;
struct Low : public LevelState {
explicit Low(Machine &m, LevelState *&state) :
LevelState(m, state) {}
void entry() { print("entering Low"); }
void liftUp() { change(s.high); }
void bringDown() { print("already Low"); }
void exit() { print("leaving Low"); }
} low;
private:
class Left;
class ColorState : public GenericState<Machine, ColorState, Left> {
protected:
explicit ColorState(Machine &m, ColorState *&state, Left &s) :
GenericState<Machine, ColorState, Left>(m, state, s) {}
public:
virtual void paint(Color color) { (void)color; unhandledEvent(); }
};
struct Red : public ColorState {
explicit Red(Machine &m, ColorState *&state, Left &s) :
ColorState(m, state, s) {}
void entry() { m.changedColor(); }
void paint(Color color);
};
struct Blue : public ColorState {
explicit Blue(Machine &m, ColorState *&state, Left &s) :
ColorState(m, state, s) {}
void entry() { m.changedColor(); }
void paint(Color color);
};
private:
class DirectionState : public GenericState<Machine, DirectionState> {
protected:
explicit DirectionState(Machine &m, DirectionState *&state) :
GenericState<Machine, DirectionState>(m, state) {}
public:
virtual void paint(Color color) { (void)color; unhandledEvent(); }
virtual void turnRight() { unhandledEvent(); }
virtual void turnLeft() { unhandledEvent(); }
} *directionState;
struct Left : public DirectionState {
friend class Red;
friend class Blue;
explicit Left(Machine &m, DirectionState *&state) :
DirectionState(m, state),
red(m, colorState, *this), blue(m, colorState, *this) {}
void entry() { ColorState::init(colorState, red); }
void paint(Color color) { colorState->paint(color); }
void turnRight() { change(s.right); }
private:
ColorState *colorState;
Red red;
Blue blue;
} left;
struct Right : public DirectionState {
explicit Right(Machine &m, DirectionState *&state) :
DirectionState(m, state) {}
void turnLeft() { change(s.left); }
} right;
};
#endif // MACHINE_H
machine.cpp
#include "machine.h"
void Machine::start()
{
LevelState::init(levelState, high);
DirectionState::init(directionState, left);
}
void Machine::Red::paint(Machine::Color color)
{
if (color == BLUE) change(s.blue);
else ColorState::paint(color);
}
void Machine::Blue::paint(Machine::Color color)
{
if (color == RED) change(s.red);
else ColorState::paint(color);
}