title: A "generalized" finite state machine implementation
body: <p>I often have the need to implement an object which is capable of switching its behaviour in response to a user command. For example, this could be the case of a class representig device connected to a PC and controlled by the user via a GUI. More generally, the device has to live on its own, with its own operation scheduling.
  <img src="https://i.stack.imgur.com/yYhZd.png" alt="enter image description here">
  Since I'd like to "extract" this behaviour from the specific device class in order to enhance code re-use, here I propose a templated finite state machine class using Qt. I also reported an example usage in class A. What do you ( more experienced programmers than me :) think about that? Is it the "correct" way to design such a class? Are there performance issues ?</p>
  
  <pre><code>template &lt; class Base,
             typename T,
             class ThreadPolicy&gt;
  class FSM
  {
  public:
      typedef bool (Base::*my_func)();
      struct SState {
          SState(){}
          SState(const T&amp; id_arg,
                 const T&amp; next_arg,
                 const T&amp; error_arg,
                 const QList&lt;T&gt;&amp; branches_arg,
                 const my_func&amp; op_arg) :
              id(id_arg),
              next(next_arg),
              error(error_arg),
              branches(branches_arg),
              op(op_arg)
          {}
          T id;       // state ID
          T next;    // next state
          T error;    // in case of error
          QList&lt;T&gt; branches; // allowed state switching from current
          my_func op; // operation associated with current state
      };
      typedef QMap&lt;T ,SState&gt; SMap;
      bool switchState(const T&amp; ns){
          return _checkAllowed(ns);
      }
      bool addState(const T&amp; id, const SState&amp; s){
          return _register(id, s);
      }
  protected:
  
      void _loop(Base* ptr){
          if ((ptr-&gt;*m_states[m_state].op)()) {
              ThreadPolicy::Lock();
              if(m_externalSwitch){
                  m_externalSwitch = false;
                  ThreadPolicy::Unlock();
                  return;
              }
              m_state = m_states[m_state].next;
              ThreadPolicy::Unlock();
          } else {
              ThreadPolicy::Lock();
              if(m_externalSwitch){
                  m_externalSwitch = false;
                  ThreadPolicy::Unlock();
                  return;
              }
              m_state = m_states[m_state].error;
              ThreadPolicy::Unlock();
          }
      }
      bool _checkAllowed(const T&amp; cmd){
          if (!m_states[m_state].branches.contains(cmd)) { return false;}
          ThreadPolicy::Lock();
          m_state = cmd;
          m_externalSwitch = true;
          ThreadPolicy::Unlock();
          return true;
      }
  
      bool _register(const SState&amp; s){
          if(m_states.find(s.id) != m_states.end()) { return false; } // state with same ID already exist
          m_states[s.id] = s; // add the new state to the map
          return true;
      }
      SMap m_states; // map states to Baseclass methods
      T m_state;  // holds my current state
      bool m_externalSwitch; // check if user request a state switch
  };
  
  class A :
          public QObject,
          public FSM&lt; A, QString, MultiThreaded &gt;
  {
      Q_OBJECT
      A(){
  //        SState startState; myState.branches &lt;&lt; "start" &lt;&lt; "stop";
          _register(SState("start",
                           "start",
                           "stop",QStringList(("start","stop")),
                           &amp;A::_doStart));
          _register(SState("stop",
                           "stop",
                           "stop",QStringList(("stop","start")),
                           &amp;A::_doStop));
      }
  
  private slots:
      void run(){
          for(;;){
              _loop(this);
              QCoreApplication::processEvents();
          }
      }
  private:
      bool _doStart(){ return true;}
      bool _doStop(){ return true;}
  
  };
  </code></pre>