【问题标题】:Jumping between sub SMs in boost::msm在 boost::msm 中的子 SM 之间跳转
【发布时间】:2015-06-18 11:56:50
【问题描述】:

我的主 SM 中有两个子 SM。我希望能够从主 SM 跳到其中一个,也可以从一个子 SM 跳到另一个 SM。但我不能。我能够从主 SM 跳转到子 SM,并从子 SM 的 一个 跳转到另一个,但是当我在子 SM 之间添加“相互”转换时,编译失败了 ~10抱怨不同事物的错误。我想那是因为编译器进入了递归旋转。

我想我可以在主 SM 中添加一个虚拟状态,并通过匿名转换到目标子 SM。但随后我会放弃触发转换的真实事件,我不想要那个(它包含数据)。

这里是一些测试代码,有问题的行被注释掉了

#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 {

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

    struct EvGotoSub1 {};
    struct EvGotoSub2 {};

    struct MainSM_;
    using Main = back::state_machine<MainSM_>;    
    struct Sub1SM_;
    using Sub1 = back::state_machine<Sub1SM_>;
    struct Sub2SM_;
    using Sub2 = back::state_machine<Sub2SM_>;

    struct Sub1SM_ : state_machine_def<Sub1SM_> {
        struct Started : state<> { };
        using initial_state = mpl::vector<Started>;
        struct transition_table:mpl::vector<
        Row<Started, EvGotoSub2, Sub2, none, none>
        > {};
    };

    struct Sub2SM_ : state_machine_def<Sub2SM_> {
        struct Started : state<> { };
        using initial_state = mpl::vector<Started>;
        struct transition_table:mpl::vector<
        // Uncomment line below to break things
        //Row<Started, EvGotoSub1, Sub1, none, none>
        > {};
    };

    struct MainSM_ : state_machine_def<MainSM_> {
        struct Started : state<> { };
        using initial_state = mpl::vector<Started>;
        struct transition_table:mpl::vector<
        Row<Started, EvGotoSub1, Sub1, none, none>,
        Row<Started, EvGotoSub2, Sub2, none, none>
        > {};
    };
}

int main() {

    Main main;
    main.start();
    main.process_event(EvGotoSub1());
    main.process_event(EvGotoSub2());
    main.process_event(EvGotoSub1());
}

【问题讨论】:

    标签: c++ boost-msm


    【解决方案1】:

    我假设您不想将Sub2 嵌套在Sub1 中,反之亦然,但两者都是Main 的子机,没有任何嵌套。 您可以使用pseudo exit states 从一台子机退出并转到另一台。

    这些退出状态只是转发传入的事件,然后您可以通过在Main 的转换表中定义额外的转换将其传递给其他子机:

    #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 {
    
        using namespace boost::msm;
        using namespace boost::msm::front;
        namespace mpl = boost::mpl;
    
        struct EvGotoSub1 { EvGotoSub1(int d1):d1(d1){} int d1;};
        struct EvGotoSub2 { EvGotoSub2(int d2):d2(d2){} int d2;};
    
        struct MainSM_;
        using Main = back::state_machine<MainSM_>;    
        struct Sub1SM_;
        using Sub1 = back::state_machine<Sub1SM_>;
        struct Sub2SM_;
        using Sub2 = back::state_machine<Sub2SM_>;
    
        struct Sub1SM_ : state_machine_def<Sub1SM_> {
            struct Started : state<> {  template <class Event,class Fsm> void on_entry(const Event& e, Fsm&) const { std::cout << "SUB2SM_ Started::on_entry(): d1="<<e.d1 << std::endl; } };
            struct Exit : exit_pseudo_state<EvGotoSub2> {};
            using initial_state = mpl::vector<Started>;
            struct transition_table:mpl::vector<
             Row<Started, EvGotoSub2, Exit, none, none>
            > {};
        };
    
        struct Sub2SM_ : state_machine_def<Sub2SM_> {
            struct Started : state<> {  template <class Event,class Fsm> void on_entry(const Event& e, Fsm&) const { std::cout << "SUB2SM_ Started::on_entry(): d2="<<e.d2 << std::endl; } };
            struct Exit : exit_pseudo_state<EvGotoSub1> {};
            using initial_state = mpl::vector<Started>;
            struct transition_table:mpl::vector<
            Row<Started, EvGotoSub1, Exit, none, none>
            > {};
        };
    
        struct MainSM_ : state_machine_def<MainSM_> {
            struct Started : state<> { };
            using initial_state = mpl::vector<Started>;
            struct transition_table:mpl::vector<
            Row<Started, EvGotoSub1, Sub1, none, none>,
            Row<Started, EvGotoSub2, Sub2, none, none>,
            Row<Sub2::exit_pt<Sub2SM_::Exit>, EvGotoSub1, Sub1, none, none>,
            Row<Sub1::exit_pt<Sub1SM_::Exit>, EvGotoSub2, Sub2, none, none>
            > {};
        };
    }
    
    
    int main() {
    
        Main main;
        main.start();
        main.process_event(EvGotoSub1(0));
        main.process_event(EvGotoSub2(1));
        main.process_event(EvGotoSub1(2));
    }
    

    现场示例:http://coliru.stacked-crooked.com/a/d491442b38a24e82

    如您所见,事件并没有丢失,而是被转发了。

    可以在http://redboltz.wikidot.com/exit-point-pseudo-state 找到关于伪退出状态的良好资源。

    【讨论】:

    • 是的,您的假设是正确的。这正是我一直在寻找的!