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;
}