Charly H.
Charly H.

Reputation: 83

Why boost::msm::front::state_machine can only support up to 10 states for its transition table?

I am trying to set up my own state machine with several states, guards and actions but when the number of states in the transition table exceeds 10 states, extensive error messages pops out but I still cannot infer the source of the error from them. I have simplified my codes as bellow:

/* Boost MSM */
#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/back/mpl_graph_fsm_check.hpp>

/* STL */
#include <memory>

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

#define None \
    msmf::none

namespace {

class Shelf_Hooking ;
// typedef msmb::state_machine<Shelf_Hooking> SM_ ;
typedef msmb::state_machine<Shelf_Hooking, msmb::mpl_graph_fsm_check> SM_ ;

struct Event {} ;

class Shelf_Hooking : public msmf::state_machine_def<Shelf_Hooking> {
    /* States */
    struct A ;
    struct B ;
    struct C ;
    struct D ;
    struct E ;
    struct F ;
    struct G ;
    struct H ;
    struct I ;
    struct J ;
    struct K ;
    struct L ;
    struct M ;
    struct End ;

public:
    Shelf_Hooking() {} ;
    ~Shelf_Hooking() {} ;
    typedef A initial_state ;

    struct transition_table : mpl::vector<
      msmf::Row < A, Event, B, None, None >
    , msmf::Row < B, None, C, None, None >
    , msmf::Row < C, None, D, None, None >
    , msmf::Row < D, None, E, None, None >
    , msmf::Row < E, None, F, None, None >
    , msmf::Row < F, None, G, None, None >
    , msmf::Row < G, None, H, None, None >
    , msmf::Row < H, None, I, None, None >
    , msmf::Row < I, None, J, None, None >
    , msmf::Row < J, None, K, None, None >
    , msmf::Row < K, None, L, None, None >
    , msmf::Row < L, None, M, None, None >
    , msmf::Row < M, None, End, None, None >
    >{} ;

private:
    struct A : public msmf::state<> {} ;
    struct B : public msmf::state<> {} ;
    struct C : public msmf::state<> {} ;
    struct D : public msmf::state<> {} ;
    struct E : public msmf::state<> {} ;
    struct F : public msmf::state<> {} ;
    struct G : public msmf::state<> {} ;
    struct H : public msmf::state<> {} ;
    struct I : public msmf::state<> {} ;
    struct J : public msmf::state<> {} ;
    struct K : public msmf::state<> {} ;
    struct L : public msmf::state<> {} ;
    struct M : public msmf::state<> {} ;
    struct End : public msmf::terminate_state<> {} ;

} ; /* End of State Machine class */

/***************************************************************/
/* Back-end */
class state_machine_impl{
    std::unique_ptr<SM_> state_machine ;

public:
    state_machine_impl() 
    : state_machine(new SM_()) {}

    ~state_machine_impl() {}

    void runSM() {
    state_machine->start() ;
    state_machine->process_event( Event() ) ;
    } /* End of runSM() */

} ; /* End of class state_machine_impl */

} /* End of namespace */

int main() {
    std::unique_ptr<state_machine_impl> Sm_= 
    std::unique_ptr<state_machine_impl>(new state_machine_impl() ) ;

    Sm_->runSM() ;
    return 0 ;
}

The transition table works if I only have all the transitions up to state J, but once I add the transition from J to K, The compiler would throw an error covering 20,000.+ lines. My question is:

How can I insert more than 10 states, guards, and actions into the transition table without creating any error?

Thank you in advance!

The compiler error messages:

Scanning dependencies of target test_multiple_states
[ 86%] Building CXX object CMakeFiles/test_multiple_states.dir/src/test_multiple_states.cpp.o
In file included from /usr/include/boost/fusion/include/as_set.hpp:11:0,
         from /usr/include/boost/msm/back/state_machine.hpp:28,
         from /home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:2:
/usr/include/boost/fusion/container/set/convert.hpp: In instantiation of ‘struct boost::fusion::result_of::as_set<boost::mpl::s_item<{anonymous}::Shelf_Hooking::K, boost::mpl::s_item<{anonymous}::Shelf_Hooking::J, boost::mpl::s_item<{anonymous}::Shelf_Hooking::I, boost::mpl::s_item<{anonymous}::Shelf_Hooking::H, boost::mpl::s_item<{anonymous}::Shelf_Hooking::G, boost::mpl::s_item<{anonymous}::Shelf_Hooking::F, boost::mpl::s_item<{anonymous}::Shelf_Hooking::E, boost::mpl::s_item<{anonymous}::Shelf_Hooking::D, boost::mpl::s_item<{anonymous}::Shelf_Hooking::C, boost::mpl::s_item<{anonymous}::Shelf_Hooking::B, boost::mpl::s_item<{anonymous}::Shelf_Hooking::A, boost::mpl::set0<> > > > > > > > > > > > >’:
/usr/include/boost/msm/back/state_machine.hpp:1169:75:   required from ‘class boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>’
/home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:94:29:   required from here
/usr/include/boost/fusion/container/set/convert.hpp:27:13: error: invalid use of incomplete type ‘struct boost::fusion::detail::barrier::as_set<11>’
         type;
         ^
In file included from /usr/include/boost/fusion/container/set/convert.hpp:11:0,
         from /usr/include/boost/fusion/include/as_set.hpp:11,
         from /usr/include/boost/msm/back/state_machine.hpp:28,
         from /home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:2:
/usr/include/boost/fusion/container/set/detail/as_set.hpp:28:12: note: declaration of ‘struct boost::fusion::detail::barrier::as_set<11>’
     struct as_set;
        ^
In file included from /home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:2:0:
/usr/include/boost/msm/back/state_machine.hpp: In instantiation of ‘boost::msm::back::state_machine<A0, A1, A2, A3, A4>::state_machine() [with A0 = {anonymous}::Shelf_Hooking; A1 = boost::msm::back::mpl_graph_fsm_check; A2 = boost::parameter::void_; A3 = boost::parameter::void_; A4 = boost::parameter::void_]’:
/home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:94:29:   required from here
/usr/include/boost/msm/back/state_machine.hpp:1591:27: error: using invalid field ‘boost::msm::back::state_machine<A0, A1, A2, A3, A4>::m_substate_list’
      ,m_substate_list()
               ^
/usr/include/boost/msm/back/state_machine.hpp: In instantiation of ‘void boost::msm::back::state_machine<A0, A1, A2, A3, A4>::call_init<Event>::operator()(const boost::msm::wrap<State>&) [with State = {anonymous}::Shelf_Hooking::A; Event = boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::InitEvent; A0 = {anonymous}::Shelf_Hooking; A1 = boost::msm::back::mpl_graph_fsm_check; A2 = boost::parameter::void_; A3 = boost::parameter::void_; A4 = boost::parameter::void_]’:
/usr/include/boost/mpl/for_each.hpp:78:26:   required from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::v_iter<boost::mpl::v_item<{anonymous}::Shelf_Hooking::A, boost::mpl::vector0<mpl_::na>, 0>, 0l>; LastIterator = boost::mpl::v_iter<boost::mpl::v_item<{anonymous}::Shelf_Hooking::A, boost::mpl::vector0<mpl_::na>, 0>, 1l>; TransformFunc = boost::msm::wrap<mpl_::arg<1> >; F = boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::call_init<boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::InitEvent>]’
/usr/include/boost/mpl/for_each.hpp:105:18:   required from ‘void boost::mpl::for_each(F, Sequence*, TransformOp*) [with Sequence = boost::mpl::v_item<{anonymous}::Shelf_Hooking::A, boost::mpl::vector0<mpl_::na>, 0>; TransformOp = boost::msm::wrap<mpl_::arg<1> >; F = boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::call_init<boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::InitEvent>]’
/usr/include/boost/msm/back/state_machine.hpp:1225:13:   required from ‘void boost::msm::back::state_machine<A0, A1, A2, A3, A4>::start() [with A0 = {anonymous}::Shelf_Hooking; A1 = boost::msm::back::mpl_graph_fsm_check; A2 = boost::parameter::void_; A3 = boost::parameter::void_; A4 = boost::parameter::void_]’
/home/charly/My_programming_exercises/finite_state_machine/src/test_multiple_states.cpp:99:30:   required from here
/usr/include/boost/msm/back/state_machine.hpp:2085:57: error: ‘boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::library_sm {aka class boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>}’ has no member named ‘m_substate_list’
         execute_entry(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
                             ^
(...)

/usr/include/boost/msm/back/state_machine.hpp:671:58: error: ‘boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>::library_sm {aka class boost::msm::back::state_machine<{anonymous}::Shelf_Hooking, boost::msm::back::mpl_graph_fsm_check>}’ has no member named ‘m_substate_list’
         (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
                              ^
CMakeFiles/test_multiple_states.dir/build.make:62: recipe for target 'CMakeFiles/test_multiple_states.dir/src/test_multiple_states.cpp.o' failed
make[2]: *** [CMakeFiles/test_multiple_states.dir/src/test_multiple_states.cpp.o] Error 1
CMakeFiles/Makefile2:400: recipe for target 'CMakeFiles/test_multiple_states.dir/all' failed
make[1]: *** [CMakeFiles/test_multiple_states.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

Upvotes: 1

Views: 839

Answers (2)

natille
natille

Reputation: 61

If running into this with 1.80.0, the documentation currently contains the following tidbit:

State objects are built automatically with the state machine. They will exist until state machine destruction. MSM is using Boost.Fusion behind the hood. This unfortunately means that if you define more than 10 states, you will need to extend the default:

#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need

Source: https://www.boost.org/doc/libs/1_80_0/libs/msm/doc/HTML/ch03s02.html

Edit: Realized this question is for functor front end, and this detail applies to the basic front end.

Upvotes: 0

sehe
sehe

Reputation: 393924

Compile with a recent boost, on c++11 compiler:

PS Don't abuse #define for type aliases

Live On Coliru (Clang)

#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/back/mpl_graph_fsm_check.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/state_machine_def.hpp>

#include <memory>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace msmb = boost::msm::back;
namespace mpl = boost::mpl;
using None = msmf::none;

namespace {

    class Shelf_Hooking;
    // typedef msmb::state_machine<Shelf_Hooking> SM_ ;
    typedef msmb::state_machine<Shelf_Hooking, msmb::mpl_graph_fsm_check> SM_;

    struct Event {};

    class Shelf_Hooking : public msmf::state_machine_def<Shelf_Hooking> {
        /* States */
        struct A;
        struct B;
        struct C;
        struct D;
        struct E;
        struct F;
        struct G;
        struct H;
        struct I;
        struct J;
        struct K;
        struct L;
        struct M;
        struct End;

      public:
        Shelf_Hooking(){};
        ~Shelf_Hooking(){};
        typedef A initial_state;

        struct transition_table : mpl::vector<
              msmf::Row<A, Event, B, None, None>, 
              msmf::Row<B, None, C, None, None>,
              msmf::Row<C, None, D, None, None>, 
              msmf::Row<D, None, E, None, None>,
              msmf::Row<E, None, F, None, None>, 
              msmf::Row<F, None, G, None, None>,
              msmf::Row<G, None, H, None, None>, 
              msmf::Row<H, None, I, None, None>,
              msmf::Row<I, None, J, None, None>, 
              msmf::Row<J, None, K, None, None>,
              msmf::Row<K, None, L, None, None>, 
              msmf::Row<L, None, M, None, None>,
              msmf::Row<M, None, End, None, None> > {};

      private:
        struct A : public msmf::state<> {};
        struct B : public msmf::state<> {};
        struct C : public msmf::state<> {};
        struct D : public msmf::state<> {};
        struct E : public msmf::state<> {};
        struct F : public msmf::state<> {};
        struct G : public msmf::state<> {};
        struct H : public msmf::state<> {};
        struct I : public msmf::state<> {};
        struct J : public msmf::state<> {};
        struct K : public msmf::state<> {};
        struct L : public msmf::state<> {};
        struct M : public msmf::state<> {};
        struct End : public msmf::terminate_state<> {};

    }; /* End of State Machine class */

    /***************************************************************/
    /* Back-end */
    class state_machine_impl {
        std::unique_ptr<SM_> state_machine;

      public:
        state_machine_impl() : state_machine(new SM_()) {}

        ~state_machine_impl() {}

        void runSM() {
            state_machine->start();
            state_machine->process_event(Event());
        } /* End of runSM() */

    }; /* End of class state_machine_impl */

} /* End of namespace */

int main() {
    std::unique_ptr<state_machine_impl> Sm_ = std::unique_ptr<state_machine_impl>(new state_machine_impl());

    Sm_->runSM();
}

Upvotes: 0

Related Questions