ARTcrime
ARTcrime

Reputation: 110

Boost msm Sub-Sub-Statemachine

i have some trouble implementing a sub-sub-statemachine with boost::msm. I'm trying to minimize my code here...

Test.cpp:

struct SM_ : StateMachineA<SM_> {};
// Pick a back-end
typedef boost::msm::back::state_machine<SM_> SM;
int main()
{
    std::cout << "Starting State Machine" << std::endl;
    SM sm1;
    //  sm1.start();
    return 0;
}

StateMachineA is defined in StateMachineA.h

namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
template<typename Derived>
struct StateMachineA: protected msmf::state_machine_def < Derived, msmf::default_base_state >
        {
        public:

            //// Entry point to state machine. 

            //// Set initial state
            typedef mpl::vector<initState, allOk> initial_state;

            //// Exit Point
            struct Exit :msmf::terminate_state<> {};

            // ----- Sub State machine
            struct SSM_ : StateMachineB<SSM_> {};

            // Pick a back-end
            typedef boost::msm::back::state_machine<SSM_> stateMachineB;


            //// Transition table
            struct transition_table : mpl::vector<
                msmf::Row < initState, go, stateMachineB, msmf::none, msmf::none >,
                msmf::Row < allOk, fatalThrown, Exit, msmf::none, msmf::none >,
                msmf::Row < error, fatalThrown, Exit, msmf::none, msmf::none >
            > {};




        protected:


            template <class FSM, class Event>
            void no_transition(Event const&, FSM&, int)
            {
                std::cout << "ERROR: Unallowed transition detected" << std::endl;
            }
        };

StateMachineB has a StateMachineC included using the exact same code (replace B by C...).

Putting StateMachineC as a submachine to StateMachineA (omitting StateMachineB) works fine. Same for A -> B without including C works fine as well. Reordering the state machines (A -> C -> B) produces the same error. To sum up: Every combination of two state machines is working, every combination of three state machines is failing. The error occurs when having SM sm1; in my main function. -> While resolving the templates? Without that line, everything compiles fine.

The error log is lengthy (long enough to cause visual studio to crash when hovering it...). First error is:

D:\boost_1_59_0\boost/mpl/aux_/push_front_impl.hpp(45) : error C2664: 'int    boost::mpl::assertion_failed<false>(boost::mpl::assert<false>::type)' : cannot convert argument 1 from 'boost::mpl::failed ************(__thiscall boost::mpl::push_front_impl<boost::mpl::aux::vector_tag<20>>::apply<Sequence,T>::REQUESTED_PUSH_FRONT_SPECIALIZATION_FOR_SEQUENCE_DOES_NOT_EXIST::* ***********)(Sequence)' to 'boost::mpl::assert<false>::type'

with ... and around 200 "with" lines to follow. After that, many errors of type:

D:\boost_1_59_0\boost/mpl/aux_/insert_impl.hpp(60) : error C3203: 'type' : unspecialized class template can't be used as a template argument for template parameter 'State', expected a real type
D:\boost_1_59_0\boost/mpl/insert.hpp(32) : error C2903: 'apply' : symbol is neither a class template nor a function template
    D:\boost_1_59_0\boost/mpl/aux_/has_type.hpp(20) : see reference to class template instantiation 'boost::mpl::insert<U1,U2,U3>' being compiled

follow.

Any ideas?

Thanks!

Upvotes: 1

Views: 1635

Answers (1)

Takatoshi Kondo
Takatoshi Kondo

Reputation: 3540

I couldn't reproduce your situation but I can show you how to implement SubSub state machine. Here is a document that I wrote. It describes about sub state machine. http://redboltz.wikidot.com/sub-machine-state

To implement SubSub state machine, just apply sub machine implementation twice.

Here is a code that contains SubSub state machine:

#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 <boost/static_assert.hpp>

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

// StateMachine [Osm]
//
// (initial)
//    |
//    V
// State1:StateSub --Event1--> State2
//
//
// StateMachine [StateSub]
//
// (initial)
//    |
//    V
// SubState1 --Event2--> SubState2:StateSubSub
//    A                          |
//    +--------Event3------------+
//
//
// StateMachine [StateSubSub]
//
// (initial)
//    |
//    V
// SubSubState1---Event4--> SubSubState2
//    A                          |
//    +-----------Event5---------+



// ----- Events
struct Event1 {};
struct Event2 {};
struct Event3 {};
struct Event4 {};
struct Event5 {};

// ----- State machine
struct StateSubSub_:msmf::state_machine_def<StateSubSub_>
{
    struct SubSubState1:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
            std::cout << "SubSubState1::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
            std::cout << "SubSubState1::on_exit()" << std::endl;
        }
    };
    struct SubSubState2:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
            std::cout << "SubSubState2::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
            std::cout << "SubSubState2::on_exit()" << std::endl;
        }
    };

    // Set initial state
    typedef mpl::vector<SubSubState1> initial_state;
    // Transition table
    struct transition_table:mpl::vector<
        //          Start      Event   Next       Action      Guard
        msmf::Row < SubSubState1, Event4, SubSubState2, msmf::none, msmf::none >,
        msmf::Row < SubSubState2, Event5, SubSubState1, msmf::none, msmf::none >
    > {};
};
typedef msm::back::state_machine<StateSubSub_> StateSubSub;


// ----- State machine
struct StateSub_:msmf::state_machine_def<StateSub_>
{
    struct SubState1:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
            std::cout << "SubState1::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
            std::cout << "SubState1::on_exit()" << std::endl;
        }
    };
    struct SubState2_:msmf::state_machine_def<SubState2_>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
            std::cout << "SubState2::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
            std::cout << "SubState2::on_exit()" << std::endl;
        }
        struct Impl_:StateSubSub {};
        typedef Impl_ initial_state;
    };
    // Pick a back-end
    typedef msm::back::state_machine<SubState2_> SubState2;

    // Set initial state
    typedef mpl::vector<SubState1> initial_state;
    // Transition table
    struct transition_table:mpl::vector<
        //          Start      Event   Next       Action      Guard
        msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
        msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
    > {};
};
typedef msm::back::state_machine<StateSub_> StateSub;

struct OuterSm_:msmf::state_machine_def<OuterSm_>
{
    struct State1_:msmf::state_machine_def<State1_>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
            std::cout << "State1::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
            std::cout << "State1::on_exit()" << std::endl;
        }
        struct Impl_:StateSub {};
        typedef Impl_ initial_state;
    };
    // Pick a back-end
    typedef msm::back::state_machine<State1_> State1;
    struct State2:msmf::state<>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
            std::cout << "State2::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
            std::cout << "State2::on_exit()" << std::endl;
        }
    };
    // Set initial state
    typedef State1 initial_state;
    // Transition table
    struct transition_table:mpl::vector<
        //          Start   Event   Next    Action      Guard
        msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
    > {};
};

// Pick a back-end
typedef msm::back::state_machine<OuterSm_> Osm;

void test()
{
    Osm osm;
    osm.start();

    std::cout << "> Send Event2()" << std::endl;
    osm.process_event(Event2());
    std::cout << "> Send Event4()" << std::endl;
    osm.process_event(Event4());
    std::cout << "> Send Event5()" << std::endl;
    osm.process_event(Event5());
    std::cout << "> Send Event3()" << std::endl;
    osm.process_event(Event3());
    std::cout << "> Send Event1()" << std::endl;
    osm.process_event(Event1());
}

int main()
{
    test();
}

You can compile, run and modify it on Wandbox, online-compiler.

https://wandbox.org/permlink/tBCSQDNhkBQkXxh0

Upvotes: 3

Related Questions