Skip to content

Does SML support state machine inheritance? #628

@cuitoldfish

Description

@cuitoldfish

Expected Behavior

In some application, there will be many instanced sharing one base state machine while each of them might extend addtional states and transistions. For example

struct BaseStateMachine {
    auto operator()() const {
        using namespace sml;
        return make_transition_table(
            *"Idle"_s + event<Start> / [] {} = "Running"_s,
            "Running"_s + event<Stop> / [] {  } = "Idle"_s,
            "Running"_s + event<Pause> / [] {  } = "Paused"_s,
            "Paused"_s + event<Resume> / [] {  } = "Running"_s
        );
    }
};

struct ExtendedStateMachine : BaseStateMachine {
    auto operator()() const {
        using namespace sml;
        return make_transition_table(
            BaseStateMachine::operator()(),  // Include base transitions
            "Running"_s + event<Abort> / [] {  } = "Aborted"_s,
            "Aborted"_s + event<Resume> / [] {  } = "Idle"_s
        );
    }
};

I hope I can create the ExtendedStateMachine and trigger some state transitions:

sml::sm<ExtendedStateMachine> sm;
sm.process_event(Start{});
sm.process_event(Abort{});

Actual Behavior

<source>: In member function 'auto ExtendedStateMachine::operator()() const':
<source>:68:37: error: no matching function for call to 'make_transition_table(boost::ext::sml::v1_1_11::aux::pool<boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'R', 'u', 'n', 'n', 'i', 'n', 'g'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'I', 'd', 'l', 'e'>(boost::ext::sml::v1_1_11::front::initial_state)>, boost::ext::sml::v1_1_11::front::event<Start>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<BaseStateMachine::operator()() const::<lambda()>, void> >, boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'I', 'd', 'l', 'e'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'R', 'u', 'n', 'n', 'i', 'n', 'g'> >, boost::ext::sml::v1_1_11::front::event<Stop>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<BaseStateMachine::operator()() const::<lambda()>, void> >, boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'P', 'a', 'u', 's', 'e', 'd'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'R', 'u', 'n', 'n', 'i', 'n', 'g'> >, boost::ext::sml::v1_1_11::front::event<Pause>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<BaseStateMachine::operator()() const::<lambda()>, void> >, boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'R', 'u', 'n', 'n', 'i', 'n', 'g'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'P', 'a', 'u', 's', 'e', 'd'> >, boost::ext::sml::v1_1_11::front::event<Resume>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<BaseStateMachine::operator()() const::<lambda()>, void> > >, boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'I', 'd', 'l', 'e'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'R', 'u', 'n', 'n', 'i', 'n', 'g'> >, boost::ext::sml::v1_1_11::front::event<Stop>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<ExtendedStateMachine::operator()() const::<lambda()>, void> >, boost::ext::sml::v1_1_11::front::transition<boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'I', 'd', 'l', 'e'> >, boost::ext::sml::v1_1_11::front::state<boost::ext::sml::v1_1_11::aux::string<char, 'P', 'a', 'u', 's', 'e', 'd'> >, boost::ext::sml::v1_1_11::front::event<Stop>, boost::ext::sml::v1_1_11::front::always, boost::ext::sml::v1_1_11::aux::zero_wrapper<ExtendedStateMachine::operator()() const::<lambda()>, void> >)'
   68 |         return make_transition_table(
      |                ~~~~~~~~~~~~~~~~~~~~~^
   69 |             BaseStateMachine::operator()(),  // Include base transitions
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   70 |             "Running"_s + event<Stop> / [] {  } = "Idle"_s,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   71 |             "Paused"_s + event<Stop> / [] {  } = "Idle"_s
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   72 |         );
      |         ~                            
In file included from <source>:3:
/app/raw.githubusercontent.com/boost-experimental/sml/master/include/boost/sml.hpp:2879:16: note: candidate: 'template<class ... Ts, typename boost::ext::sml::v1_1_11::aux::enable_if<boost::ext::sml::v1_1_11::aux::is_same<boost::ext::sml::v1_1_11::aux::bool_list<boost::ext::sml::v1_1_11::aux::always<Ts>::value ...>, boost::ext::sml::v1_1_11::aux::bool_list<boost::ext::sml::v1_1_11::concepts::transitional<Ts>::value ...> >::value, int>::type <anonymous> > constexpr auto boost::ext::sml::v1_1_11::make_transition_table(Ts ...)'
 2879 | constexpr auto make_transition_table(Ts... ts) {
      |                ^~~~~~~~~~~~~~~~~~~~~
/app/raw.githubusercontent.com/boost-experimental/sml/master/include/boost/sml.hpp:2879:16: note:   template argument deduction/substitution failed:
/app/raw.githubusercontent.com/boost-experimental/sml/master/include/boost/sml.hpp:89:85: error: no type named 'type' in 'struct boost::ext::sml::v1_1_11::aux::enable_if<false, int>'
   89 | #define __BOOST_SML_REQUIRES(...) typename aux::enable_if<__VA_ARGS__, int>::type = 0
      |                                                                                     ^
/app/raw.githubusercontent.com/boost-experimental/sml/master/include/boost/sml.hpp:2877:24: note: in expansion of macro '__BOOST_SML_REQUIRES'
 2877 | template <class... Ts, __BOOST_SML_REQUIRES(aux::is_same<aux::bool_list<aux::always<Ts>::value...>,
      |                        ^~~~~~~~~~~~~~~~~~~~
Compiler returned: 1

Does SML support this kind of usage?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions