Skip to content

boost::mp11::mp_list can't be used as base class for transition table within msm::front::state_machine_def #63

@PiotrNycz

Description

@PiotrNycz

I just wanted to modernize my code - and try to use boost::mp11::mp_list instead of boost::mpl::vector in my FSM definitions.

Simplified code is as follows:

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

#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/mpl.hpp>

namespace msm = boost::msm;

namespace test_fsm 
{
struct play {};
struct stop {};
struct player_ : public msm::front::state_machine_def<player_>
{
    typedef int no_exception_thrown;
    typedef int no_message_queue;

    struct Empty : public msm::front::state<> 
    {
        template <class Event,class FSM>   void on_entry(Event const&,FSM& ) { std::cout << "entering: Empty" << std::endl; }
        template <class Event,class FSM>   void on_exit(Event const&,FSM& ) { std::cout << "leaving: Empty" << std::endl; }
    };
    struct Playing : public msm::front::state<>
    {
        template <class Event,class FSM>    void on_entry(Event const&,FSM& ) { std::cout << "entering: Playing" << std::endl; }
        template <class Event,class FSM>    void on_exit(Event const&,FSM& ) { std::cout << "leaving: Playing" << std::endl; }
    };

    typedef Empty initial_state;

    // transition actions
    void playing(play const&)  {  }
    void stop_playing(stop const&)  {  }
    
    typedef player_ p; 

    struct transition_table : boost::mp11::mp_list<
            _row < Empty , play        , Playing       >,
            _row < Playing , stop        , Empty       >
    > {};

    // Replaces the default no-transition response.
    template <class FSM,class Event>
    void no_transition(Event const& e, FSM&,int state)
    {
        std::cout << "no transition from state " << state
            << " on event " << typeid(e).name() << std::endl;
    }

    typedef msm::back::state_machine<player_> player;

    //
    // Testing utilities.
   //
   static char const* const state_names[] = { "Empty", "Playing" };

    void pstate(player const& p)
   {
       std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
   }
};

}

int main()
{
    test_fsm::player p2;
    p2.start();
    p2.process_event(test_fsm::play());
    p2.process_event(test_fsm::stop()); 
    return 0;
}

It compiles, but produces unexpected output:

entering: Empty
no transition from state 0 on event N8test_fsm4playE
no transition from state 0 on event N8test_fsm4stopE

While - with original version (just replacing mp11::mp_list with mpl::vector) it works as expected:

entering: Empty
leaving: Empty
entering: Playing
leaving: Playing
entering: Empty

It also works as expected with boost::fusion::vector.

I found one workaround - when using type-alias for defining transition table it works as expected:

    using transition_table = boost::mp11::mp_list<
            _row < Empty , play        , Playing       >,
            _row < Playing , stop        , Empty       >
    > ;

With type-alias it also works for other types boost::mpl::vector and boost::fustion::vector.

I am not sure what this inheritance is for, but all examples from boost::msm defines this transition tables that way.

The problem with boost::mp11::mp_list is probably here <boost/mp11/mpl.hpp> - but I am not sure that.

I asked the question about that on SO: https://stackoverflow.com/questions/68195912/boostmp11mp-list-cant-define-proper-transition-table-for-fsm-based-on-boost - but not get much attention.

You can play with the problem on compiler explorer: https://godbolt.org/z/jTEnxPMTj

The problem is not related to version of boost or compiler.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions