boost::msm 用法:如何设置目标状态的属性

boost::msm usage: how to set properties of target states

本文关键字:目标 状态 属性 设置 用法 msm 何设置 boost      更新时间:2023-10-16

我的FSM中的状态具有不同的属性。我定义了一个事件,该事件将调用到目标状态的转换。我想按事件数据设置目标的属性。我的选择是:1. 在操作或防护中设置属性:但它仍处于源状态。如果我在当时设置目标状态属性,我填写不好2.在目标条目中设置属性:但是属性的值已在收到事件时进行了保护,因此我应该再次重新计算:(

任何人都可以给我更多的想法。谢谢!

我不确定您的情况,但我认为您有两个不同的问题。一个是设置目标状态属性的最佳位置。另一个是如何避免重新计算。

让我们考虑前一个问题。正如你提到的,有两个候选人。它们是转换操作和目标状态的进入操作。我认为两者都可以。如果使用目标状态的条目操作,则需要关注事件类型。如果按如下方式编写处理程序,则处理程序将捕获所有事件。

    template <class Event, class Fsm>
    void on_entry(Event const& e, Fsm&) {
        std::cout << "State2::on_entry()" << std::endl;
        std::cout << "You can also set the property here." << std::endl;
        property = e.data;
    }

您可以按如下方式指定事件:

    template <class Fsm>
    void on_entry(Event1 const& e, Fsm&) {
        std::cout << "State2::on_entry()" << std::endl;
        std::cout << "You can also set the property here." << std::endl;
        property = e.data;
    }

为了解决后一个问题,如何避免重新计算,你需要在事件中将成员变量声明为可变的,如下所示:

    struct Event1 {
        mutable int data; // mutable is required because Event is passed as const&.
    };

因为 Boost.MSM 将事件参数作为常量引用传递。

下面是描述如何在不重新计算的情况下设置目标状态属性的代码:

#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 <boost/static_assert.hpp>
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// StateMachine [Sm]
//
// (initial)
//    |
//    V
// State1 --Event1[Guard1]/Action1--> State2
//
// ----- Events
struct Event1 {
    mutable int data; // mutable is required because Event is passed as const&.
};
struct Sm_:msmf::state_machine_def<Sm_>
{
    // States
    struct State1:msmf::state<>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            std::cout << "State1::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            std::cout << "State1::on_exit()" << std::endl;
        }
    };
    struct State2:msmf::state<>
    {
        template <class Event,class Fsm>
        void on_entry(Event const& e, Fsm&) {
            std::cout << "State2::on_entry()" << std::endl;
            std::cout << "You can also set the property here." << std::endl;
            property = e.data;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            std::cout << "State2::on_exit()" << std::endl;
        }
        int property;
    };
    // Set initial state
    typedef State1 initial_state;
    // Guards
    struct Guard1 {
        template <class Event, class Fsm, class Source, class Target>
        bool operator()(Event const& e, Fsm&, Source&, Target&) const {
            e.data *= 2; // calc
            std::cout << "In Guard1, e.data *= 2. e.data=" << e.data << std::endl;
            return true;
        }
    };
    // Actions
    struct Action1 {
        template <class Event, class Fsm, class Source, class Target>
        void operator()(Event const& e, Fsm&, Source&, Target& t) const {
            std::cout << "In Action1, set target state property based on event data that is calculated in Guard1." << std::endl;
            t.property = e.data;
        }
    };
    // Transition table
    struct transition_table:mpl::vector<
        //          Start   Event   Next    Action      Guard
        msmf::Row < State1, Event1, State2, Action1,    Guard1 >
    > {};
};
// Pick a back-end
typedef msm::back::state_machine<Sm_> Sm;
void test()
{
    Sm sm;
    sm.start();
    std::cout << "> Send Event1()" << std::endl;
    Event1 e1;
    e1.data = 12;
    sm.process_event(e1);
}
int main()
{
    test();
}

您可以使用在线编译器 Wandbox 编译、运行和修改代码。http://melpon.org/wandbox/permlink/L1HAjIiLU091906u