0

我希望能够将数据从事件传递到由于转换而构建的状态。

从2009年的这篇文章和2010 年的这篇triggering_event()文章中建议使用。但是,我在任何地方都找不到演示如何使用它的示例。

任何人都可以帮忙吗?

4

1 回答 1

0

以下示例是基于此处描述的电机状态机的 Boost 状态图实现。我没有使用 custom_reaction 将速度从 EvSetSpeed 事件中拉出(如此处的其他状态),而是将其修改为在 Start 状态的构造函数中调用 triggering_event() 。

注意事项:

  1. boost statechart 的旧文档在此处指出:“triggering_event 的调用者需要进行类型检查或强制转换返回值”,因为 triggering_event 返回一个 const event_base 指针。
  2. 在构造过程中调用 triggering_event 需要调用状态从 state 派生,而不是 simple_state。这是因为 triggering_event 正在从构造函数访问状态机。对于它的价值,我还注意到文档指出,使用 triggering_event 通常意味着状态机设计存在问题,应该避免。
  3. 也许更熟悉 boost statechart 的人可以对此发表评论,但我发现如果我希望它转换为 Running(如我的反应列表所述),我必须在 Start 状态构造函数中重新发布触发事件。

最后值得一提的是,尝试在状态机初始状态的构造函数中调用 triggering_event 会导致返回 null 值。这是因为初始状态是在调用initial期间构建的,没有触发事件。

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/in_state_reaction.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/mpl/list.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <iostream>

namespace mpl = boost::mpl;
namespace sc = boost::statechart;

class EvHalt : public sc::event< EvHalt > {};
class EvSetSpeed : public sc::event< EvSetSpeed >
{
public:
    EvSetSpeed(int speed) : _speed(speed) {}
    int getSpeed() const { return _speed; };

private:
    int _speed;
};

class Idle;
class Start;
class Stop;
class Running;

class Motor : public sc::state_machine<Motor, Idle> {};

class Idle : public sc::simple_state<Idle, Motor>
{
public:
    typedef mpl::list<
        sc::transition< EvSetSpeed, Start >,
        sc::transition< EvHalt, Idle > > reactions;

    Idle() { std::cout << "Entering Idle State" << std::endl; };
    ~Idle() { std::cout << "Exiting Idle State" << std::endl; };
};

class Start : public sc::state<Start, Motor>
{
public:
    typedef mpl::list<
        sc::transition< EvSetSpeed, Running >,
        sc::transition< EvHalt, Stop  > > reactions;

    Start(my_context ctx) : _speed(0), my_base(ctx)
    { 
        auto trigEvt = dynamic_cast<const EvSetSpeed*>(triggering_event());
        if (trigEvt) // returns true if trigEvt is indeed an EvSetSpeed event
        {
            _speed = trigEvt->getSpeed();
            post_event(*trigEvt);
            std::cout << "Entering Start State at speed " << _speed << std::endl;
        }
        else
            std::cout << "Entering Start State. Triggering Event is NOT EvSetSpeed." << std::endl;
    };
    ~Start() { std::cout << "Exiting Start State" << std::endl; };
private:
    int _speed;  // Unused in this example.
};

class Running : public sc::simple_state<Running, Motor>
{
public:
    typedef mpl::list<
        sc::custom_reaction< EvSetSpeed >,
        sc::custom_reaction< EvHalt  > > reactions;

    sc::result react(const EvSetSpeed& ev)
    {
        std::cout << "In Running Mode: Set Speed to " << ev.getSpeed() << std::endl;
        return discard_event();
    }
    sc::result react(const EvHalt& ev)
    {
        std::cout << "In Running Mode: Halting Motor" << std::endl;
        post_event(ev);
        return transit<Stop>();
    }

    Running() { std::cout << "Entering Running State" << std::endl; };
    ~Running() { std::cout << "Exiting Running State" << std::endl; };
};

class Stop : public sc::simple_state<Stop, Motor>
{
public:
    typedef sc::transition< EvHalt, Idle > reactions;

    Stop() { std::cout << "Entering Stop State" << std::endl; };
    ~Stop() { std::cout << "Exiting Stop State" << std::endl; };
};

int main()
{
    Motor myMotor;
    myMotor.initiate();
    myMotor.process_event(EvSetSpeed(100));
    myMotor.process_event(EvSetSpeed(200));
    myMotor.process_event(EvHalt());
    myMotor.process_event(EvSetSpeed(300));
    myMotor.process_event(EvHalt());
    myMotor.process_event(EvHalt());
    return 0;
}
于 2016-11-20T18:52:46.160 回答