gpt4 book ai didi

c++ - 如何使用 boost::msm 的前向声明来避免循环依赖?

转载 作者:行者123 更新时间:2023-11-28 01:33:13 24 4
gpt4 key购买 nike

我正在尝试使用 boost::msm 实现一个简单的协议(protocol)。当数据包到达时,它们会被处理并发送到状态机 (SM) 以进行相应处理。

我的 pkt 类(即 Pkt1)需要 fsm 的句柄,允许它调用 fsm->process_event(...)(当然我会添加 #include “myfsm.h” 到 pkt1.h 的顶部)。

到目前为止一切顺利。但是,如果我的状态机(比如 State1)需要通过自己发送数据包来对该数据包使用react怎么办?现在,我会将“pkt1.h” header 包含到“state1.h”的顶部,这样我就可以创建 Pkt1 的实例并调用其 send() 函数。

你可能会猜到这个最终包含会导致“循环依赖”

可以找到示例代码(有错误):https://wandbox.org/permlink/IlFsUQyLPLrLl2RW (第一次用wandbox,希望一切顺利)

注意)在“state1.h”文件中删除#include "pkt1.h" & on_entry(..)... Pkt1 pkt; pkt.send(); 使其可编译。

Questions:

1) 我应该如何解决这种循环依赖?

2) 我认为前进的方向是为我的 Pkt1 类添加一个实现文件 (.cpp) 并将 #include "myfsm.h" 传输到该文件,从而打破循环依赖。但是如何在头文件中转发声明MyFsm呢?

3) 我是 boost::msm/CRTP 的新手,代码让我感到困惑。当我没有将相应的 header 包含到 state1.h 时,State1 如何访问 MyFsm? (可能是因为 MyFsm 派生自仿函数前端/后端,其中包含其 header 并允许虚函数调用相应的 MyFsm 函数!!??)

非常感谢您抽出宝贵时间提前提供帮助。

包含的代码:

  • 事件.h

    #ifndef EVENTS
    #define EVENTS


    // ----- Events
    struct Event1 {};
    struct Event2 {};

    #endif // EVENTS
  • main.cpp

    #include <iostream>

    #include "events.h"
    #include "myfsm.h"
    #include "pkt1.h"

    int main()
    {
    MyFsm fsm;
    fsm.start();

    //fsm.process_event(Event1());
    Pkt1 rcvdPkt;
    rcvdPkt.dispatch(&fsm);

    return 0;
    }
  • myfsm.h

    //MyFsm.h
    #ifndef MYFSM
    #define MYFSM

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

    #include "state1.h"
    #include "state2.h"
    #include "events.h"

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


    struct MyFsm_ : msmf::state_machine_def<MyFsm_>
    {
    struct State1_ : State1 {}; // use public inheritance
    struct State2_ : State2 {}; // use public inheritance

    // Set initial state
    typedef State1_ initial_state;

    // Transition table
    struct transition_table:mpl::vector<
    msmf::Row < State1_, Event1, State2_, msmf::none, msmf::none >
    >{};
    };
    // Pick a back-end
    typedef msm::back::state_machine<MyFsm_> MyFsm;


    #endif // MYFSM
  • pkt1.h

    #ifndef PKT1
    #define PKT1

    #include "myfsm.h"
    #include "events.h"

    class Pkt1
    {
    public:
    Pkt1() {}

    void dispatch(MyFsm *fsm){
    fsm->process_event(Event1());
    }

    void send(){std::cout<<"pkt1 sent out ..."<<std::endl;}

    };

    #endif // PKT1
  • state1.h

    //State1.h
    #ifndef STATE1
    #define STATE1

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

    #include "pkt1.h" //comment this line to resolve the compliation error

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

    struct State1:msmf::state<>
    {
    // Entry action
    template <class Event,class Fsm>
    void on_entry(Event const&, Fsm& ) const {
    std::cout << "State1::on_entry()" << std::endl;
    Pkt1 pkt; pkt.send();//comment this line to resolve the compliation error
    }
    // Exit action
    template <class Event,class Fsm>
    void on_exit(Event const&, Fsm&) const {
    std::cout << "State1::on_exit()" << std::endl;
    }
    };

    #endif // STATE1
  • 状态2.h

    //State2.h
    #ifndef STATE2
    #define STATE2

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

    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;
    struct State2:msmf::state<>
    {
    // Entry action
    template <class Event,class Fsm>
    void on_entry(Event const&, Fsm&) const {
    std::cout << "State2::on_entry()" << std::endl;
    }
    // Exit action
    template <class Event,class Fsm>
    void on_exit(Event const&, Fsm&) const {
    std::cout << "State2::on_exit()" << std::endl;
    }
    };

    #endif // STATE2

最佳答案

1) How should I resolve this circular dependency?

2) I think the way forward would be to add an implementation file (.cpp) for my Pkt1 class and transfer the #include "myfsm.h" to this file, thus breaking the circular dependency. But how can I forward declare the MyFsm in the header file?

正确。在 Pkt1.h 中,您将转发声明 MyFsm,但它只是某个模板化 boost 类型的 typedef。这里最简单的方法是复制 typedef(或使用),同时转发声明您正在使用的类作为模板参数:

#include <boost/msm/back/state_machine.hpp>

struct MyFsm_;
using MyFsm = boost::msm::back::state_machine<MyFsm_>;

(如果你多次使用这部分,你可能应该把它放在一个标题中以避免代码重复)。

然后将所有函数实现移动到 Pkt1.cpp 中,同时将声明保留在 header 中。这是可行的,因为(或只要)你在那里的所有函数只接受对 MyFsm 的指针或引用,因为此时编译器只需要知道“它是一个指针”。

Pkt1.h:

#include <boost/msm/back/state_machine.hpp>

struct MyFsm_;
using MyFsm = boost::msm::back::state_machine<MyFsm_>;


class Pkt1
{
public:
Pkt1() {}

void dispatch(MyFsm *fsm);

void send();
};

Pkt1.cpp:

#include "pkt1.h"

#include "myfsm.h"
#include "events.h"

#include <iostream>

void Pkt1::dispatch(MyFsm *fsm)
{
fsm->process_event(Event1());
}

void Pkt1::send()
{
std::cout<<"pkt1 sent out ..."<<std::endl;
}

演示:https://wandbox.org/permlink/5zMsbolOMPN0biaY

3) I am new to boost::msm/CRTP and the code is confusing to me. How can State1 get access to MyFsm while I have not included the corresponding header to state1.h?? (maybe because MyFsm derives from the functor front/back end which its header is included and allows virtual functions to call the corresponding MyFsm functions!!??)

这里的关键是on_entryon_exit模板 函数。它们的代码仅在它们被使用时生成——例如在 FSM 实现中(在 boost 中,我们在这里看不到)。这就是它们必须位于 header 中的原因:当编译器实例化(即为其实例生成代码)函数模板时,完整的函数体必须对编译器可见。在这一点上,模板参数 Fsm 被替换为 MyFsm(以及您的事件之一的 Event),因此一切都是已知的并且可以解决。

我建议阅读翻译单元以及 C/C++ 编译器如何生成代码(即 .h.cpp 文件会发生什么)。一旦您了解了这一点,很多事情就会水到渠成。

关于c++ - 如何使用 boost::msm 的前向声明来避免循环依赖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50678963/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com