Reputation: 1130
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.
Upvotes: 1
Views: 4493
Reputation: 859
This is rather old now, but in case someone else stumbles upon this looking for an answer:
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.
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.
Upvotes: 4