Boost MSM:使用状态机本身作为隐式顶级状态

Boost MSM: using state machine itself as implicit top level state

我有一个状态机,状态为 ABCC 直接处理事件 e,而 AB 不处理,但我想回退到默认处理程序(Samek 称之为 "ultimate hook" 模式)对于事件 e(当在状态 AB 中找不到处理程序时将调用该事件)。但是,使用 Boost MSM,我无法在状态机级别实现此处理程序,但必须引入一个额外的容器状态 S,其中包含 ABC

有没有办法直接在状态机级别本身实现事件处理程序而不需要此容器状态?

您可以使用 no_transition 处理程序来做到这一点。

假设事件 E 定义如下:

struct E {
    int val = 42;
};

这是事件 E 的 no_transition 处理程序示例:

template <typename Fsm> 
void no_transition(E const& e, Fsm&, int state) {
    std::cout << "no transition at state " << state << " event e.val" << e.val << std::endl;
}

但是,由于元编程,Boost.MSM 需要 no_transition 其他类型的处理程序。

因此您需要为其他事件定义 no_transition 处理程序,如下所示:

template <typename Fsm, typename Event> 
void no_transition(Event const&, Fsm& ,int) {
    std::cout << "shouldn't be called but need to define to compile" << std::endl;
}

您可能认为您可以执行以下操作:

template <typename Fsm, typename Event> 
void no_transition(Event const&, Fsm& ,int) {
    std::cout << "no transition at state " << state << " event e.val" << e.val << std::endl;
}

它不起作用,因为 no_transition 处理程序不仅实例化了 E,还实例化了其他没有成员变量 val.

的事件

以下是基于您的问题的完整工作代码示例:

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

// ----- Events
struct E {
    int val = 42;
};
struct AtoB {};
struct BtoC {};

// ----- State machine
struct Sm1_:msmf::state_machine_def<Sm1_>
{
    // States
    struct A:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "A::on_entry()" << std::endl;
        }
    };
    struct B:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "B::on_entry()" << std::endl;
        }
    };
    struct C:msmf::state<> {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "C::on_entry()" << std::endl;
        }
    };

    // Set initial state
    using initial_state = A;

    // Transition table
    struct transition_table:mpl::vector<
        //          Start   Event   Next  Action      Guard
        msmf::Row < A,      AtoB,   B,    msmf::none, msmf::none >,
        msmf::Row < B,      BtoC,   C,    msmf::none, msmf::none >,
        msmf::Row < C,      E,      A,    msmf::none, msmf::none >
    > {};

    template <typename Fsm> 
    void no_transition(E const& e, Fsm&, int state) {
        std::cout << "no transition at state " << state << " event e.val" << e.val << std::endl;
    }

    template <typename Fsm, typename Event> 
    void no_transition(Event const&, Fsm& ,int) {
        std::cout << "shouldn't be called but need to define to compile" << std::endl;
    }
};

// Pick a back-end
using Sm1 =  msm::back::state_machine<Sm1_>;

int main() {
    Sm1 sm1;
    sm1.start(); 
    std::cout << "> Send Event E" << std::endl;
    sm1.process_event(E());
    std::cout << "> Send Event AtoB" << std::endl;
    sm1.process_event(AtoB());
    std::cout << "> Send Event E" << std::endl;
    sm1.process_event(E());
    std::cout << "> Send Event BtoC" << std::endl;
    sm1.process_event(BtoC());
    std::cout << "> Send Event E" << std::endl;
    sm1.process_event(E());
}

现场演示:https://wandbox.org/permlink/NWvuaetwFAm5Nm23