Re: [Boost-users] [MSM] Boost.MSM: statemachine to transition on templatized event-type

Hi,
having tested Boost.MSM, I'm pretty happy with it.
:)
It's interesting, in that it seems to handle all states in a static table. No "new" operator etc.
It's much faster without dynamic allocation. <snip> g_row<StateInitial, EventT, StateEven, &Machine_<EventT>::guardToEven>,
Unfortunately gcc gives this error: d.cpp:119:5: error: ‘g_row’ was not declared in this scope g_row<StateInitial, EventT, StateEven, &Machine_<EventT>::guardToEven>,
Short answer. Try: typename Machine_<EventT>::template g_row<StateFloat, EventT, StateFloat, &Machine_<EventT>::guardToFloat> Long answer: g_row is a type of state_machine_def and as your fsm is a template, it becomes a dependent type (=> typename) and a template one even (=> template). C++ is sometimes really annoying :( Longer answer. Give up this front-end, it's deprecated anyway. A better solution will be: #include <boost/msm/front/functor_row.hpp> using namespace boost::msm::front; struct GuardToOdd { template <class EVT,class FSM,class SourceState,class TargetState> bool operator()(EVT const& num,FSM& ,SourceState& ,TargetState& ) { const long long x = static_cast<long long>(num.getNum()); return ((x == num.getNum()) // is Integral type && ((x % 2) != 0)); } }; Row< StateFloat, EventT, StateOdd, none, GuardToOdd> HTH, Christophe

On Fri, May 29, 2015 at 4:00 PM, Christophe Henry < christophe.j.henry@gmail.com> wrote:
Hi,
having tested Boost.MSM, I'm pretty happy with it.
:)
It's interesting, in that it seems to handle all states in a static
table.
No "new" operator etc.
It's much faster without dynamic allocation.
<snip>
g_row<StateInitial, EventT, StateEven, &Machine_<EventT>::guardToEven>,
Unfortunately gcc gives this error: d.cpp:119:5: error: ‘g_row’ was not declared in this scope g_row<StateInitial, EventT, StateEven, &Machine_<EventT>::guardToEven>,
Short answer. Try:
typename Machine_<EventT>::template g_row<StateFloat, EventT, StateFloat, &Machine_<EventT>::guardToFloat>
Thanks so much for taking the time to help out! This works perfectly!!!
Long answer: g_row is a type of state_machine_def and as your fsm is a template, it becomes a dependent type (=> typename) and a template one even (=> template).
C++ is sometimes really annoying :(
Longer answer. Give up this front-end, it's deprecated anyway. A better solution will be:
#include <boost/msm/front/functor_row.hpp> using namespace boost::msm::front;
struct GuardToOdd { template <class EVT,class FSM,class SourceState,class TargetState> bool operator()(EVT const& num,FSM& ,SourceState& ,TargetState& ) { const long long x = static_cast<long long>(num.getNum()); return ((x == num.getNum()) // is Integral type && ((x % 2) != 0)); } };
Row< StateFloat, EventT, StateOdd, none, GuardToOdd>
I've tried it! Nice, thanks.
HTH, Christophe
I have a question about optimization regarding guard conditions. How can one optimize the states and guard-checking?? This is one way: /// see full working code example at the bottom of this post struct transition_table : mpl::vector< Row<StateInitial, EventT, StateEven, none, none>, Row<StateInitial, EventT, StateOdd, none, GuardToOdd>, Row<StateInitial, EventT, StateFloat, none, GuardToFloat>, Row<StateEven, EventT, StateEven, none, none>, Row<StateEven, EventT, StateOdd, none, GuardToOdd>, Row<StateEven, EventT, StateFloat, none, GuardToFloat>, Row<StateOdd, EventT, StateEven, none, none>, Row<StateOdd, EventT, StateOdd, none, GuardToOdd>, Row<StateOdd, EventT, StateFloat, none, GuardToFloat>, Row<StateFloat, EventT, StateEven, none, none>, Row<StateFloat, EventT, StateOdd, none, GuardToOdd>, Row<StateFloat, EventT, StateFloat, none, GuardToFloat> >{}; which relies on the guard-checking from the bottom to the top (first guard returning true wins). The guards can then be: struct GuardToOdd { template <class EVT, class FSM, class SourceState, class TargetState> bool operator()(EVT const& num, FSM&, SourceState&, TargetState&) { const long long x = static_cast<long long>(num.getNum()); /* do not have to check if number is float or integral here. Reason: GuardToFloat is guaranteed to be false if we are here, because it is lower in transition_table !!!!!! */ return ((x % 2) != 0); } }; struct GuardToFloat { template <class EVT, class FSM, class SourceState, class TargetState> bool operator()(EVT const& num, FSM&, SourceState&, TargetState&) { const long long x = static_cast<long long>(num.getNum()); return (x != num.getNum()); // is Floating type } }; But the transition table is still huge. Is it possible to use MSM to create a parentstate "StateEval" with substates "StateEven", "StateOdd", "StateFloat" ?, the idea being to make transition_table as short as possible. Something like this maby (but it does not work): struct transition_table : mpl::vector< Row<StateEval, EventT, StateEval::StateEven, none, none>, Row<StateEval, EventT, StateEval::StateOdd, none, GuardToOdd>, Row<StateEval, EventT, StateEval::StateFloat, none, GuardToFloat> >{}; Basically: is it possible to create a parentstate, that listens to events (even when an inner substate is already active)? Thanks. nicesw123 Full code-example (using large transition_table): #include <iostream> #include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/back/state_machine.hpp> #include <boost/msm/front/functor_row.hpp> using namespace boost::msm::front; namespace msm = boost::msm; namespace mpl = boost::mpl; // events struct EventNumber1 { // int number! EventNumber1(int num_) : num{num_} {} int getNum() const { return num; } private: int num; }; struct EventNumber2 { // double number! EventNumber2(double num_) : num{num_} {} double getNum() const { return num; } private: double num; }; typedef EventNumber2 MyEvent; // using doubles // StateBase -- a base (parent) state struct StateBase : public msm::front::state<> { StateBase(const std::string& stateName = "") : stateName{stateName} {} template <typename Event, typename FSM> void on_entry(const Event&, FSM&) { std::cout << "Entering " << stateName << std::endl; } template <typename Event, typename FSM> void on_exit(const Event&, FSM&) { std::cout << "Leaving " << stateName << std::endl; } private: std::string stateName; }; template <typename T> struct StateMachineFront_Base : public msm::front::state_machine_def<StateMachineFront_Base<T>> { StateMachineFront_Base(const std::string& stateMachineName = "") : stateMachineName{stateMachineName} {} template <typename Event, typename FSM> void on_entry(const Event&, FSM&) { std::cout << "Entering " << stateMachineName << std::endl; } template <typename Event, typename FSM> void on_exit(const Event&, FSM&) { std::cout << "Leaving " << stateMachineName << std::endl; } private: std::string stateMachineName; }; //guards struct GuardToOdd { template <class EVT, class FSM, class SourceState, class TargetState> bool operator()(EVT const& num, FSM&, SourceState&, TargetState&) { const long long x = static_cast<long long>(num.getNum()); return ((x % 2) != 0); } }; struct GuardToFloat { template <class EVT, class FSM, class SourceState, class TargetState> bool operator()(EVT const& num, FSM&, SourceState&, TargetState&) { const long long x = static_cast<long long>(num.getNum()); return (x != num.getNum()); // is Floating type } }; template <typename EventT> struct Machine_ : public StateMachineFront_Base<Machine_<EventT> > { Machine_(const std::string& stateMachineName = "Machine_") : StateMachineFront_Base<Machine_<EventT> >{stateMachineName} {} // states struct StateInitial : public StateBase { StateInitial(const std::string name = "StateInitial") : StateBase{name} {} }; struct StateEven : public StateBase { StateEven(const std::string name = "StateEven") : StateBase{name} {} }; struct StateOdd : public StateBase { StateOdd(const std::string name = "StateOdd") : StateBase{name} {} }; struct StateFloat : public StateBase { StateFloat(const std::string name = "StateFloat") : StateBase{name} {} }; typedef StateInitial initial_state; struct transition_table : mpl::vector< Row<StateInitial, EventT, StateEven, none, none>, Row<StateInitial, EventT, StateOdd, none, GuardToOdd>, Row<StateInitial, EventT, StateFloat, none, GuardToFloat>, Row<StateEven, EventT, StateEven, none, none>, Row<StateEven, EventT, StateOdd, none, GuardToOdd>, Row<StateEven, EventT, StateFloat, none, GuardToFloat>, Row<StateOdd, EventT, StateEven, none, none>, Row<StateOdd, EventT, StateOdd, none, GuardToOdd>, Row<StateOdd, EventT, StateFloat, none, GuardToFloat>, Row<StateFloat, EventT, StateEven, none, none>, Row<StateFloat, EventT, StateOdd, none, GuardToOdd>, Row<StateFloat, EventT, StateFloat, none, GuardToFloat> >{}; }; typedef msm::back::state_machine<Machine_<MyEvent>> Machine; template <typename T> void postEvents(Machine& machine) { for (T i; std::cin >> i; ) { machine.process_event(MyEvent{i}); } } int main() { Machine machine; machine.start(); postEvents<double>(machine); machine.stop(); return 0; }

Hi,
I have a question about optimization regarding guard conditions. How can one optimize the states and guard-checking??
<snip>
Is it possible to use MSM to create a parentstate "StateEval" with substates "StateEven", "StateOdd", "StateFloat" ?, the idea being to make transition_table as short as possible.
Something like this maby (but it does not work
struct transition_table : mpl::vector< Row<StateEval, EventT, StateEval::StateEven, none, none>, Row<StateEval, EventT, StateEval::StateOdd, none, GuardToOdd>, Row<StateEval, EventT, StateEval::StateFloat, none, GuardToFloat>
{};
Basically: is it possible to create a parentstate, that listens to events (even when an inner substate is already active)?
Thanks.
nicesw123
I think what you want is a composite state / submachine (http://www.boost.org/doc/libs/1_58_0/libs/msm/doc/HTML/ch02s02.html#d0e151). You want a submachine named StateEval and 3 substates inside, called StateEven, StateOdd, and StateFloat. Then you want 3 direct entries (which I dislike as it is a fsm goto, please consider direct entry transitions, on the above page). Then you save some transitions by having in your current fsm transitions originate from StateEval instead of substates. Correct? Then yes, it works of course. See: http://www.boost.org/doc/libs/1_58_0/libs/msm/doc/HTML/ch03s02.html#d0e529. There is also an example (http://www.boost.org/doc/libs/1_58_0/libs/msm/doc/HTML/examples/CompositeTut...) which also supports the functor front end. About entries, you could look at: http://www.boost.org/doc/libs/1_58_0/libs/msm/doc/HTML/ch03s02.html#d0e875. HTH, Christophe
participants (3)
-
Christophe Henry
-
christophe.j.henry@gmail.com
-
nice sw123