In my project, there is a state machine implemented using boost meta state machine. This main state machine, there is a state (let's call it SubMachineEntry
for simplicity) that represents an entry point to a sub state machine:
namespace msmf = boost::msm::front;
namespace msmb = boost::msm::back;
...
msmf::Row < SomeState, enterSub, SubMachineEntry, msmf::none, msmf::none >
...
using SubMachine = msmb::state_machine<SubMachine_>;
This sub state machine performs some processing and then we go back to the outer state machine, to state
using SubMachineFinished = SubMachine::exit_pt<...>;
, which represents the exit state of the sub machine. My problem is that, before the sub state machine exits, a certain event (toProcessInOuter
) might be dispatched, and it should be processed in outer state machine after sub state machine exits. Putting that event as deferred in all states in the sub state machine does not work, it is not propagated to the state that comes after SubMachineFinished
. Is there a way to implement this forwarding of the event using some mechanism of the boost MSM, without using some custom workaround?
Unfortunately, deferred events at sub-machine cannot evaluate at the parent state-machine on MSM. So you need to write the defer transition at the parent state.
Events are evaluated from the inner state-machine to the outer state-machine. If you want to defer the event, you can write the defer transition in the parent state. I wrote the example that demonstrate it.
See the attached diagram. Let's say Event2
is the event that you want to defer. You need to write the defer transition to State1
.
Here is the whole code:
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// ----- Events
struct Event1 {};
struct Event2 {};
// ----- State machine
struct OuterSm_:msmf::state_machine_def<OuterSm_> {
struct State1_:msmf::state_machine_def<State1_> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) const {
std::cout << "State1::on_entry()" << std::endl;
}
template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "State1::on_exit()" << std::endl;
}
struct SubState1:msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) const {
std::cout << "SubState1::on_entry()" << std::endl;
}
template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "SubState1::on_exit()" << std::endl;
}
};
template <class Fsm,class Event>
void no_transition(Event const& e, Fsm& ,int state) {
std::cout << "No handled event in InnerSm " << typeid(e).name() << " on State " << state << std::endl;
}
struct Exit1:msmf::exit_pseudo_state<msmf::none> {};
// Set initial state
typedef mpl::vector<SubState1> initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < SubState1, Event1, Exit1, msmf::none, msmf::none >
> {};
};
struct State2:msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) const {
std::cout << "State2::on_entry()" << std::endl;
}
template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "State2::on_exit()" << std::endl;
}
};
template <class Fsm,class Event>
void no_transition(Event const& e, Fsm& ,int state) {
std::cout << "No handled event in OuterSm " << typeid(e).name() << " on State " << state << std::endl;
}
typedef msm::back::state_machine<State1_> State1;
// Actions
struct Action {
template <class Event, class Fsm, class SourceState, class TargetState>
void operator()(Event const&, Fsm&, SourceState&, TargetState&) const {
std::cout << "Action()" << std::endl;
}
};
// enable deferred events
typedef int activate_deferred_events;
// Set initial state
typedef State1 initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < State1::exit_pt
<State1_::Exit1>, msmf::none, State2, msmf::none, msmf::none >,
msmf::Row < State1, Event2, msmf::none, msmf::Defer, msmf::none >,
msmf::Row < State2, Event2, msmf::none, Action, msmf::none >
> {};
};
// Pick a back-end
typedef msm::back::state_machine<OuterSm_> Osm;
int main() {
Osm osm;
osm.start();
std::cout << "> Send Event2()" << std::endl;
osm.process_event(Event2());
std::cout << "> Send Event1()" << std::endl;
osm.process_event(Event1());
return 0;
}
Running demo: https://wandbox.org/permlink/WQixcoGGQwAWou34