2

I have edited my post by adding an example. You can find the header, source, and main on this link. Minimized:

#include <boost/sml.hpp>
#include <iostream>
using namespace boost::sml;

struct Start {};
struct GoNested {};

struct Ts3 {
    auto operator()() {
        return make_transition_table(
                *"nested_s3"_s + event<Start> = "Ts3_1"_s,
                "nested_s3"_s + boost::sml::on_entry<_> / [] { std::puts("---- nested_s3 ----"); },
                "Ts3_1"_s + boost::sml::on_entry<_> / [] { std::puts("---- Ts3_1 ----"); }
                );
    }
};
struct Ts2 {
    auto operator()() {
        return make_transition_table(
                *"nested_s2"_s + event<Start> = "Ts2_1"_s,
                "Ts2_1"_s + event<GoNested> = state<Ts3>,
                "nested_s2"_s + boost::sml::on_entry<_> / [] { std::puts("---- nested_s2 ----"); },
                "Ts2_1"_s + boost::sml::on_entry<_> / [] { std::puts("---- Ts2_1 ----"); });
    }
};
struct Ts1 {
    auto operator()() {
        return make_transition_table(
                *"s1"_s + event<Start> = "s2"_s,
                "s2"_s + event<GoNested> = state<Ts2>,
                "s1"_s + boost::sml::on_entry<_> / [] { std::puts("---- s1 ----"); },
                "s2"_s + boost::sml::on_entry<_> / [] { std::puts("---- s2 ----"); }
                );
    }
};

int main() {
    boost::sml::sm<Ts1, Ts2, Ts3> sMachine_;

    auto print = [&] {
        auto vis = [](auto state) { std::cout << "Current state = " << state.c_str() << std::endl; };
        sMachine_.visit_current_states(vis);
    };

    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print();
}

Printing

---- s1 ----
Current state = s1
---- s2 ----
Current state = s2
---- nested_s2 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- Ts2_1 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- nested_s3 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- Ts3_1 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >

I have 3 nested transitions tables (Ts#), each of them at a given level => Ts1(Ts2(Ts3)))

Meaning that the highest and first transition table called is Ts1 and the more the program move further, the more the state machine goes into Ts2 and then Ts3. Obviously, each transition table has its own state.

I am trying to get the current state from a given transition table but I don't succeed to get it if it is in ts2 or ts3.

This below piece of code

sMachine_.visit_current_states([](auto state) {
    std::cout << state.c_str() << std::endl; });

works only if I am at the first transition table (Ts1), otherwise, I got the following string instead of the state name:

boost::ext::sml::v1_1_4::back::sm<boost::ext::sml::v1_1_4::back::sm_policy<Ts2> >

Do you have any solution to get it correctly?

The above reproducible example depicts the problem by building and running the "testsSM.cpp" main file.

Many thanks in advance,

sehe
  • 374,641
  • 47
  • 450
  • 633
adr1611
  • 31
  • 2
  • Please show the relevant code - see https://stackoverflow.com/help/minimal-reproducible-example – sehe Jun 03 '23 at 03:02
  • @sehe Thank for you help. I have updated my question with piece of code that reprocuce my problem. Many thanks in advance. – adr1611 Jun 05 '23 at 11:59
  • always include relevant code in the question. We should not have to search for relevant code on a site that we might not want to trust. – sehe Jun 05 '23 at 12:12
  • And now I've spent all my available time getting it minimal and compiling. Hopefully someone else can help you along the way from here: http://coliru.stacked-crooked.com/a/6d67a7f539ab734a – sehe Jun 05 '23 at 12:34
  • 1
    Thank you very much @sehe ! I never really posted something here, so thank you for your help and guidance! Hopefullfy someone can find a solution easier with your updates. – adr1611 Jun 06 '23 at 13:05
  • No answer, from anyone. @sehe, would you have any guess ? Many thanks for you help. – adr1611 Jun 13 '23 at 07:07

1 Answers1

0

Minimal solution

In order to visit nested states, you need a more advanced visitor than the simple lambda function you have in place. In the examples of the boost sml library you can find a visitor implemented as follows:

template <typename StateMachine>
class StateVisitor
{
public:
  explicit StateVisitor(const StateMachine &state_machine) : state_machine_{state_machine} {}

  template <typename CompositeState>
  void operator()(boost::sml::aux::string<boost::sml::sm<CompositeState>>) const
  {
    std::cout << boost::sml::aux::get_type_name<CompositeState>() << ':';
    state_machine_.template visit_current_states<boost::sml::aux::identity<CompositeState>>(*this);
  }

  template <typename AnyOtherState>
  void operator()(AnyOtherState state) const
  {
    std::cout << AnyOtherState::c_str() << '\n';
  }

private:
  const StateMachine &state_machine_;
};

You can apply that visitor by changing your print lambda like this:

  auto print = [&]
  {
    StateVisitor<decltype(sMachine_)> visitor(sMachine_);
    sMachine_.visit_current_states(visitor);
  };

Be aware that the visitor is applied recursively. This is necessary because boost sml implements composite states as its own state machines. That means each state containing at least one nested state is itself a state machine. The function can handle composite states accordingly by providing an overloaded dedicated to composite states.

If you are happy with accessing the string representation of states you are done now.

Bonus solution

If you would like to access the specific type of a state you might extend the visitor as follows. This is especially useful if you define states as structs because this way you can access those structs statically.

template <typename StateMachine>
class BonusStateVisitor
{
public:
  explicit BonusStateVisitor(const StateMachine &state_machine) : state_machine_{state_machine} {}

  // Overload to handle states that have nested states
  template <typename CompositeState>
  void operator()(boost::sml::aux::string<boost::sml::sm<CompositeState>>) const
  {
    std::cout << boost::sml::aux::get_type_name<CompositeState>() << ':';
    state_machine_.template visit_current_states<boost::sml::aux::identity<CompositeState>>(*this);
  }

  // Overload to handle states without nested states and defines as: "state"_s
  template <char... Chars>
  void operator()(boost::sml::aux::string<boost::sml::aux::string<char, Chars...>> string_state) const
  {
    std::cout << string_state.c_str() << '\n';
  }

  // Overload to handle terminate states
  void operator()(boost::sml::aux::string<boost::sml::back::terminate_state> terminate_state) const
  {
    std::cout << terminate_state.c_str() << '\n';
  }

  // Overload to handle internal states
  void operator()(boost::sml::aux::string<boost::ext::sml::v1_1_8::front::internal>) const
  {
    // ignore internal states
  }

  // Overload to handle any other states, meaning states that are defined as: struct state{};)
  template <typename TSimpleState>
  void operator()(boost::sml::aux::string<TSimpleState>) const
  {
    std::cout << boost::sml::aux::get_type_name<TSimpleState>() << '\n';
  }

private:
  const StateMachine &state_machine_;
};
mahush
  • 31
  • 4