I know there are several implementation of FSM in C++ containing different set of features and written in different styles. Nevertheless, I've decided to write my own.
Here are some key points :
- c++17 (not later)
 - no need for the state.entry / state.exit functionality
 - number of states ≤ 10
 - I find it quite convenient to represent FSM as a class when states and transitions have access to data members
 
fsm.hpp
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <type_traits>
template<class TMachine, typename TEvent, typename TState, TState initial>
struct FSM
{
    static_assert(std::is_enum<TEvent>::value);
    static_assert(std::is_enum<TState>::value);
    typedef bool (TMachine::*EventAction_t)();
    typedef void (TMachine::*TransitionAction_t)();
    struct Transition
    {
        TState              from;
        TEvent              event;
        TState              to;
        TransitionAction_t  action { &TMachine::noAction };
    };
    typedef std::map<TState, EventAction_t> StateMap;
    typedef std::vector<Transition> TransitionList;
    void process(const TEvent event)
    {
        auto it = std::find_if(transitions.begin(), transitions.end(),
                                      [event, this](const auto& tr)
                                      {
                                        return tr.event == event and tr.from == currentState;
                                      });
        if(it == transitions.end())
            return;
        (static_cast<TMachine*>(this)->*(it->action))();
        currentState = it->to;
    }
    bool step()
    {
        if(states.find(currentState) == states.end())
            return false;
        return (static_cast<TMachine*>(this)->*states[currentState])();
    }
    void noAction()
    {
        std::cout << "No action\n"; // debug
    }
    static TransitionList transitions;
    static StateMap states;
    TState currentState { initial };
};
Usage
Let's implement the coffee machine :
#include <iostream>
#include <cstdint>
#include "fsm.hpp"
enum class State_t : uint8_t
{
    eIdle,
    eWait4Money,
    eWait4Coffee,
    ePowerOff,
};
enum class Event_t : uint8_t
{
    eMoneyInserted,
    eCoffeeButtonPressed,
    eTimeoutElapsed,
    ePowerOff,
};
struct CoffeeMachine : public FSM<CoffeeMachine, Event_t, State_t, State_t::eIdle>
{
    bool onIdle()
    {
        std::cout << "FSM :: I'm waiting for a new customer ($ earned: " << moneyEarned << ")\n";
        return true;
    }
    bool onWait4Money()
    {
        std::cout << "FSM :: Insert money, please\n";
        return true;
    }
    bool onWait4Coffee()
    {
        std::cout << "FSM :: Choose a beverage, please\n";
        return true;
    }
    bool onPowerOff()
    {
        std::cout << "FSM :: I need some sleep, goodbye...\n";
        return false;
    }
    void onMoneyInserted()
    {
        moneyEarned++;
    }
    unsigned int moneyEarned = 0;
};
template<>
CoffeeMachine::StateMap FSM<CoffeeMachine, Event_t, State_t, State_t::eIdle>::states =
{
    { State_t::eIdle,           &CoffeeMachine::onIdle },
    { State_t::eWait4Money,     &CoffeeMachine::onWait4Money },
    { State_t::eWait4Coffee,    &CoffeeMachine::onWait4Coffee },
    { State_t::ePowerOff,       &CoffeeMachine::onPowerOff },
};
template<>
CoffeeMachine::TransitionList FSM<CoffeeMachine, Event_t, State_t, State_t::eIdle>::transitions = {
      // From                   // Event                        // To                   // Action
    { State_t::eIdle,           Event_t::eCoffeeButtonPressed,  State_t::eWait4Money },
    { State_t::eIdle,           Event_t::ePowerOff,             State_t::ePowerOff },
    { State_t::eWait4Money,     Event_t::ePowerOff,             State_t::ePowerOff },
    { State_t::eWait4Money,     Event_t::eMoneyInserted,        State_t::eWait4Coffee,  &CoffeeMachine::onMoneyInserted },
    { State_t::eWait4Money,     Event_t::eTimeoutElapsed,       State_t::eIdle },
    { State_t::eWait4Coffee,    Event_t::eCoffeeButtonPressed,  State_t::eIdle },
    { State_t::eWait4Coffee,    Event_t::eTimeoutElapsed,       State_t::eIdle },
};
int main()
{
    CoffeeMachine fsm;
    while(fsm.step())
    {
        std::cout << "Choose your destiny [p - power, m - money, c - coffee] : ";
        char input = 't';
        std::cin >> input; 
        Event_t e = Event_t::eTimeoutElapsed;
        switch(input)
        {
            case 'p' :
                e = Event_t::ePowerOff;
                break;
            case 'm' :
                e = Event_t::eMoneyInserted;
                break;
            case 'c' :
                e = Event_t::eCoffeeButtonPressed;
                break;
            default :
                e = Event_t::eTimeoutElapsed;
                break;
        }
        fsm.process(e);
    }
    return 0;
}
I don't like the boilerplate of the specialization of the state and transition list, but I cannot see how I could do it less verbose. So what do you think?
