5

I want to split the implementation of boost::msm statemachine into multiple files. I am looking for sth like:

1) One header per State

2) One header for the main state-machine (the out-most SM) But I don't know how this file should be written

3) the client code that uses the SM.

What I've come up with follows (which does not compile, giving errors in the form of : "invalid use of incomplete type" & other errors).

The first Sample state:

//State1.h
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

struct State1:msmf::state<> 
{
    // Entry action
    template <class Event,class Fsm>
    void on_entry(Event const&, Fsm&) const {
        std::cout << "State1::on_entry()" << std::endl;
    }
    // Exit action
    template <class Event,class Fsm>
    void on_exit(Event const&, Fsm&) const {
        std::cout << "State1::on_exit()" << std::endl;
    }
};

The 2nd Sample state:

//State2.h
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
struct State2:msmf::state<> 
{
   // Entry action
   template <class Event,class Fsm>
   void on_entry(Event const&, Fsm&) const {
   std::cout << "State2::on_entry()" << std::endl;
   }
   // Exit action
   template <class Event,class Fsm>
   void on_exit(Event const&, Fsm&) const {
        std::cout << "State2::on_exit()" << std::endl;
   }
};

The Main SM:

//MyFsm.h
#include <iostream>
#include <boost/msm/back/state_machine.hpp>     
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

#include "state1.h"
#include "state2.h"     

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

// ----- Events
struct Event1 {};
struct Event2 {};

struct MyFsm_ : msmf::state_machine_def<MyFsm_>
{    
    struct State1;//??? is this the correct way
    struct State2;//???

   // Set initial state
   typedef State1 initial_state;

   // Transition table
   struct transition_table:mpl::vector<
   ...
   >{};
};
// Pick a back-end
typedef msm::back::state_machine<MyFsm_> MyFsm;

The client Code:

//main.h
#include "myfsm.h"

int main()
{
   MyFsm fsm;
   fsm.start();

   fsm.process_event(Event1());
} 

Any help and hint on how to split a boost:msm into multiple files is appreciated.

qwa
  • 123
  • 10

1 Answers1

4

You can introduce State1 and State2 to MyFsm using public inheritance as follows:

struct MyFsm_ : msmf::state_machine_def<MyFsm_>
{    
    struct State1_ : State1 {}; // use public inheritance
    struct State2_ : State2 {}; // use public inheritance

   // Set initial state
   typedef State1_ initial_state;

   // Transition table
   struct transition_table:mpl::vector<
         msmf::Row < State1_, Event1, State2_, msmf::none, msmf::none >
   >{};
};

In MyFsm_, use State1_ and State2_ instead of State1 and State2.

I updated your code, then it works.

Here is running demo: https://wandbox.org/permlink/ZrIVQY38C51fZNFY

You can see whole source code. The tab is corresponding to the header files. The left most one has fixed name prog.cc. Is is usually used to place int main().

Takatoshi Kondo
  • 3,111
  • 17
  • 36
  • How can I access the data of my statemachine from within the state, when defined in another header file; I have no problem when the state is implemented in the body of the SM directly. Should I use forward decleration of the main FSM to get access to it or ... ? `//myfsm.h struct MyFsm_ : msmf::state_machine_def {.... MyData smData; }; //state1.h struct State1 : msmf::state<> { template void on_entry(Event const&, Fsm& fsm) { MyFsm_& sm = static_cast(fsm); sm.smData.print(); } };` – qwa May 30 '18 at 13:36
  • Oh, as simple as that; we can use the reference passed to the state (i.e. Fsm& sm) directly to access the data in the SM (no casting required!). But then what is the point in the following assertion in some of the examples: `BOOST_STATIC_ASSERT((boost::is_convertible::value));` Thanks again. – qwa May 31 '18 at 05:15
  • I guess that the example has sub-machine state. In this case, msm passed correct state-machine (parent or sub). But user sometimes got confused. So that static assert helps to find mistakes at the compile time. – Takatoshi Kondo May 31 '18 at 13:28
  • thanks like ever; your tutorials at http://redboltz.wikidot.com/boost-msm-guide are great . – qwa Jun 02 '18 at 11:51