In the following example, while the current execution is still in substate1, I want to pass data to substate1 continuously and then send Event3 or Event1 based on the data. Looks like MSM supports only sending events using (process_event()), but I am not sure how to send data continuously to the current state.
#include
#include
#include
#include
namespace {
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// ----- Events
struct Event1 {};
struct Event2 {};
struct Event3 {};
// ----- State machine
struct OuterSm_:msmf::state_machine_def
{
struct State1_:msmf::state_machine_def
{
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State1::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State1::on_exit()" << std::endl;
}
struct SubState1:msmf::state<> {
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState1::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState1::on_exit()" << std::endl;
}
};
struct SubState2:msmf::state<> {
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState2::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState2::on_exit()" << std::endl;
}
};
// Set initial state
typedef mpl::vector initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
> {};
};
struct State2:msmf::state<>
{
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State2::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State2::on_exit()" << std::endl;
}
};
typedef msm::back::state_machine State1;
// Set initial state
typedef State1 initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
> {};
};
// Pick a back-end
typedef msm::back::state_machine Osm;
void test()
{
Osm osm;
osm.start();
std::cout << "> Send Event2()" << std::endl;
osm.process_event(Event2());
std::cout << "> Send Event1()" << std::endl;
osm.process_event(Event1());
}
}
int main()
{
test();
return 0;
}
Output:
State1::on_entry()
SubState1::on_entry()
> Send Event2()
SubState1::on_exit()
SubState2::on_entry()
> Send Event1()
SubState2::on_exit()
State1::on_exit()
State2::on_entry()
解决方案
You can use get_state to retrieve a state from the state machine and then you can call an arbitrary method on that state, e.g. sendData() in the following modification of your example (live example):
#include
#include
#include
#include
namespace {
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// ----- Events
struct Event1 {};
struct Event2 {};
struct Event3 {};
// ----- State machine
struct OuterSm_:msmf::state_machine_def
{
struct State1_:msmf::state_machine_def
{
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State1::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State1::on_exit()" << std::endl;
}
struct SubState1:msmf::state<> {
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState1::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState1::on_exit()" << std::endl;
}
void sendData(const std::string& data)
{
std::cout << "data received in Substate1:" << data << std::endl;
}
};
struct SubState2:msmf::state<> {
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState2::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "SubState2::on_exit()" << std::endl;
}
};
// Set initial state
typedef mpl::vector initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
> {};
};
struct State2:msmf::state<>
{
template
void on_entry(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State2::on_entry()" << std::endl;
}
template
void on_exit(Event const&, Fsm&) const {
BOOST_STATIC_ASSERT((boost::is_convertible::value));
std::cout << "State2::on_exit()" << std::endl;
}
};
typedef msm::back::state_machine State1;
// Set initial state
typedef State1 initial_state;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
> {};
};
// Pick a back-end
typedef msm::back::state_machine Osm;
void test()
{
Osm osm;
osm.start();
Osm::State1& state1 = osm.get_state<:state1>();
Osm::State1::SubState1& substate1 = state1.get_state<:state1::substate1>();
substate1.sendData("hello from outside");
std::cout << "> Send Event2()" << std::endl;
osm.process_event(Event2());
std::cout << "> Send Event1()" << std::endl;
osm.process_event(Event1());
}
}
int main()
{
test();
return 0;
}
Output:
State1::on_entry()
SubState1::on_entry()
data received in Substate1:hello from outside
> Send Event2()
SubState1::on_exit()
SubState2::on_entry()
> Send Event1()
SubState2::on_exit()
State1::on_exit()
State2::on_entry()