【问题标题】:Boost MSM with constructor parameters on a submachine在子机上使用构造函数参数提升 MSM
【发布时间】:2021-02-24 16:04:55
【问题描述】:

我正在尝试在主状态机和子状态机之间共享SyncBox 对象。理想的方法是将它传递给构造函数(在更复杂的情况下,子状态机将是区域之一的初始状态)。无论如何,我无法使这段代码正确编译和执行。有什么帮助吗?

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

【问题讨论】:

  • 您的所有基类都有正确的模板参数吗?对我来说看起来像是 CRTP 类型的东西,因此,例如,期望 class SubSM 将自己作为模板参数传递给基类
  • @wreckgar23 不确定你的意思
  • @wreckgar23 对我来说看起来不错。它是一个 CRTP,但是是分层的(从后端 defs 派生的前端机器)
  • @AndrewBloom 我说的是模板参数被传递给你从中派生状态机的类。在本地编译时,transition_table 抱怨 SubSM 不是默认可构造的
  • 我得到“错误 C2668 'boost::msm::back::state_machine::state_machine': 在 Visual Studio 2019 和 boost 1.75.0 上的 MainSM() 定义中对重载函数的模糊调用,但我尝试了很多变体并遇到了像你这样的其他一些错误。

标签: c++ boost boost-msm


【解决方案1】:

据我所知,你的一切都是正确的。

然而,问题在于子状态列表要求所有状态元素都是默认可构造的。 (据我所知,对于前端类来说,这可能不是真的,但还没有完全研究它)。

这意味着将引用存储为成员是禁止的。我建议改为存储一个指针。

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

它确实按预期工作:

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

打印

SubSMFE constructor

【讨论】:

  • 感谢@sehe,我在这个问题上得出的结论与我的 cmets 大致相同。我很困惑你的代码是用 g++ 编译的,我用 Visual Studio 也试过了,但它仍然会引发错误。在我看来可能是一个错误(我在 msm 的错误跟踪器上发布了它:github.com/boostorg/msm/issues/33)你有什么想法吗?我发现临时解决方法是在 mainSMFE 上有一个带有虚拟参数的构造函数。
  • 你能分享一下有效的代码吗?也许我们可以在这里测试godbolt.org/z/8bse6r 提出问题也是个好主意。最终可能是 MSVC 问题。
  • 这是我工作的解决方法的代码:coliru.stacked-crooked.com/a/52cad36200f6b95b。解决方法是添加第 44 行并更改第 54 行。这似乎解决了构造函数调用的歧义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 2021-03-12
相关资源
最近更新 更多