简体   繁体   中英

C++ Boost SML Library

I am trying to understand the library, and I am confused by what the high level idea of certain event types are. I have been reading the tutorial guide here: Boost Experimental Documentation. . It is often using types like on_exit, on_entry and _, which I do not understand.

struct _ {}; // I don't understand how to use this

template <class T, class TEvent = T>
struct on_entry : internal_event, entry_exit { // A setup function that runs before the actual event
    // ...

template <class T, class TEvent = T>
struct on_exit : internal_event, entry_exit { // Will run after the event has completed.
    // ...

struct anonymous : internal_event { // Not sure, I think this is for any unknown type that you have not defined.

My end goal is that I want to be able to have a generic event handler. A src_state might have a specific handler for E1, but for E2, E3, and so on, I want there to be a generic handler. I have the code below to list what I want to happen, but obviously it does not work.

#include <boost/sml.hpp>
#include <cassert>
#include <iostream>

namespace sml = boost::sml;

namespace {
struct e1 {};
struct e2 {};
struct e3 {};
struct e4 {};

struct transitions {
    auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
        *"idle"_s                  / [] { std::cout << "anonymous transition" << std::endl; } = "s1"_s
        , "s1"_s + event<e1>        / [] { std::cout << "internal s1 transition" << std::endl; }
        , "s1"_s + event<e2>        / [] { std::cout << "self transition" << std::endl; } = "s2"_s
        , "s1"_s + event<_>         / [] { std::cout << "s1 Handle all other events here" << std::endl; } = "s1"_s
        , "s2"_s + event<e2>        / [] {std::cout << "internal s2 transition" << std::endl; }
        , "s2"_s + event<_>         / [] { std::cout << "s2 Handle all other events here" << std::endl; } = "s2"_s
        , "s2"_s + event<e3>        / [] { std::cout << "external transition" << std::endl; } = X
);
    }
};
}

int main() {
    sml::sm<transitions> sm;
    sm.process_event(e1{}); // Basic
    sm.process_event(e3{}); // The underscore should handle the event now...
    sm.process_event(e2{}); // Transition to s2
    sm.process_event(e1{}); // The _ should handle this.
    sm.process_event(e4{}); // The _ should handle this.
    sm.process_event(e3{}); // X

    assert(sm.is(sml::X));
}

Is it even possible to have a generic event handler for ALL events, including expected and unexpected events. The state machine does expect e1/e2/e3/e4 to happen at times.

This is rather old now, but in case someone else stumbles upon this looking for an answer:

Generic Handler

In the documentation at time of writing this, what you want to achieve can be done via unexpected event handlers. These will perform the action and you're free to cause a transition to another state, but you don't need to.

The _(underscore)

I'm very reluctant to say anything about this as it is all my own interpretation and I'd rather hear it from someone that has spent more time in the code and understands it better.

From what I see in the link above and my experiments, it can be used to "match" all events that haven't been declared with specific handlers.

Entry/Exit events

#include <boost/sml.hpp>
#include <iostream>

struct state_machine {
public:
  // Transition table
  auto operator() () const {
    using namespace boost::sml;
    return make_transition_table(
      *"state_a"_s + event<event_1> = "state_b"_s,
      "state_a"_s + event<event_2> = "state_b"_s,
      "state_b"_s + on_entry<event_1> / ActionOne{},
      "state_b"_s + on_entry<_> / ActionTwo{}
    );
  }

  // Events
  struct event_1 {};
  struct event_2 {};

  // Actions
  struct ActionOne {
    void operator()() {
      std::cout << "Transition due to event_1" << std::endl;
    };
  };

  struct ActionTwo {
    void operator()() {
      std::cout << "Transition due to event_2" << std::endl;
    };
  };
};

int main () {
  boost::sml::sm<state_machine> fsm_one, fsm_two;

  // Will invoke ActionOne
  fsm_one.process_event(state_machine::event_1{});

  // Will invoke ActionTwo
  fsm_two.process_event(state_machine::event_2{});

  return 0;
}

Unexpected events

I believe the code in the link to the documentation above is clear enough and I don't need to post a working example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM