Boost MSM with constructor parameters on a submachine

459 Views Asked by At

I'm trying to share the SyncBox object between a main state-machine and a sub state-machine. The ideal way is to pass it on the constructor (sub state machine will be a initial state of one of the regions in a more complex case). No matter what, I can't make this code compile and execute properly. Any help?

#include <iostream>
#include <mutex>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>

namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front;

class SyncBox {
    std::mutex mtx;
};

struct SubSMFE : public msm::front::state_machine_def<SubSMFE>
{
    struct InitState : public msm::front::state<> {};
    struct FakeState : public msm::front::state<> {};
    typedef InitState initial_state;
    struct transition_table : mpl::vector<
        Row < InitState, none, FakeState>
    > {};
};

//typedef msm::back::state_machine<SubSMFE> SubSM;
class SubSM : public msm::back::state_machine<SubSMFE> {
private:
    SyncBox& sb;
public:
    SubSM(SyncBox& sb) : sb(sb) { std::cout << "SubSMFE constructor" << std::endl; };
    void oneFunction() {
        // here i use syncBox. it must be a function of SubSM, not SubSMFE (oneFunction overrides start or enqueue_event)
    };
};

struct mainSMFE : public msm::front::state_machine_def<mainSMFE>
{
protected:
    SyncBox sb;
public:
    struct InitState : public msm::front::state<> {};
    typedef InitState initial_state;
    struct transition_table : mpl::vector<
        Row < InitState, none, SubSM>
    > {};
};

class mainSM : public msm::back::state_machine<mainSMFE> {
public:
    mainSM() : msm::back::state_machine<mainSMFE>(msm::back::states_ << SubSM(sb)) { };
};

int main()
{
    mainSM sm;
    return 0;
}
1

There are 1 best solutions below

3
On BEST ANSWER

As far as I can tell you had everything correctly.

The problem, however, is that the substate-list requires all state elements to be default-constructible regardless. (This might not be true for the frontend class, as far as I can tell, but haven't looked all the way into it).

This means that storing a reference as member is off-limits. What I'd suggest instead is storing a pointer.

class SubSM : public msm::back::state_machine<SubSMFE> {
  private:
    SyncBox* psb = nullptr;

  public:
    SubSM() = default;

    SubSM(SyncBox& psb)
        : psb(&psb)
    {
        std::cout << "SubSMFE constructor" << std::endl;
    };

It does work as expected:

Live On Coliru

#include <boost/msm/back/state_machine.hpp>
//#include <boost/msm/front/euml/common.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <iostream>
#include <mutex>

namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front;

class SyncBox {
    std::mutex mtx;
};

struct SubSMFE : public msm::front::state_machine_def<SubSMFE> {
    struct InitState : public msm::front::state<> { };
    struct FakeState : public msm::front::state<> { };
    using initial_state = InitState;
    // clang-format off
    struct transition_table : mpl::vector<
        Row < InitState, none, FakeState>
    > {};
    // clang-format on
};

// typedef msm::back::state_machine<SubSMFE> SubSM;

class SubSM : public msm::back::state_machine<SubSMFE> {
  private:
    SyncBox* psb = nullptr;

  public:
    SubSM() = default;

    explicit SubSM(SyncBox& psb)
        : psb(&psb)
    {
        std::cout << "SubSMFE constructor" << std::endl;
    };

    void oneFunction() {
        // here i use syncBox. it must be a function of SubSM, not SubSMFE
        // (oneFunction overrides start or enqueue_event)
    };
};

class mainSMFE : public msm::front::state_machine_def<mainSMFE> {
  protected:
    SyncBox sb;

  public:
    struct InitState : public msm::front::state<> { };
    using initial_state = InitState;
    // clang-format off
    struct transition_table : mpl::vector<
        Row < InitState, none, SubSM >
    > {};
    // clang-format on
};

class mainSM : public msm::back::state_machine<mainSMFE> {
  public:
    mainSM()
        : msm::back::state_machine<mainSMFE>(
            msm::back::states_ << SubSM(sb)) {};
};

int main() {
    mainSM sm;
}

Prints

SubSMFE constructor