c++ - Boost Statechart - 本地转换

标签 c++ boost boost-statechart

我希望有人能帮我解决这个问题,或者至少指出我方法的错误...

作为我的问题的简单说明,请考虑应用程序的一部分,您可以在其中进入“功能模式”操作状态。根据用户按下的功能键 F1-F4,可以使用四种子模式。默认情况下,进入 F1 模式。状态图开始如下:

Diagram 1

用户可以随时按F1-F4切换到相应的模式。将这些转换添加到内部状态会导致以下结果:

Diagram 2

显然这是 (a) 一团糟,并且 (b) 有很多转换要定义。如果在某个时候我想添加一个 F5Mode 那么......好吧,你明白了。为避免这种情况,我想执行以下操作:

Diagram 3

Boost Statechart 允许我定义从 FunctionMode 到任何内部状态的转换,但结果不是我所期望的。实际结果如下:

Diagram 4

即按 F1-F4 切换模式会导致退出和重新进入外部 FunctionMode 状态,同时触发不需要的退出和进入操作。

回到 2006 年,this thread图书馆作者和用户之间似乎描述了同样的问题。我认为作者建议执行以下操作作为解决方法:

Diagram 5

但是,这个变通办法对我来说似乎不太吸引人:它增加了一个额外的状态级别来编译,代码变得不那么可读,必须使用深层历史来返回到任何功能模式子状态和中间状态对象被不必要地破坏并再次构造。

所以...我哪里出错了?或者有什么选择?我已经简要了解了 Boost Meta State Machine (msm),但就我目前所见,我更喜欢 Statechart 的外观。

我很惊讶更多的用户没有遇到同样的问题......这让我觉得我的方法可能是完全错误的!

最佳答案

你看过in-state reaction了吗?在 statechart tutorial 中解释?它似乎在做您正在寻找的事情。

由于您要求替代方案,在此期间我正在评估各种 C++ Harel 状态图实现。我查看了 Boost 状态图和 Boost MSM。我用两者编写了代码。他们伤害了我虚弱的大脑:-)

然后我找到Machine Objects (Macho) ,非常简单和小巧,我喜欢它。它支持分层状态机、进入/退出操作、历史记录、状态机快照、守卫、内部转换、事件延迟、状态本地存储(具有可选持久性),因此对我来说这是一个令人满意的 Harel 状态图实现。

此代码使用 Macho 实现了状态图的 FunctionMode 部分:

#include "Macho.hpp"

#include <exception>
#include <iostream>
using namespace std;

namespace FunctionMode {

struct FunctionMode;
struct F1Mode;
struct F2Mode;

// The Top state, containing all the others.
TOPSTATE(Top) {
    STATE(Top)
    // All the events of the state machine are just virtual functions.

    // Here we throw to mean that no inner state has implemented the event
    // handler and we consider that an error. This is optional, we could
    // just have an empty body or log the error.
    virtual void evF1() { throw std::exception(); }
    virtual void evF2() { throw std::exception(); }
    // evF3 and so on...
private:
    void init() { setState<FunctionMode>(); } // initial transition
};

SUBSTATE(FunctionMode, Top) {
    STATE(FunctionMode)
    virtual void evF1() { setState<F1Mode>(); }
    virtual void evF2() { setState<F2Mode>(); }
    // evF3, ...
private:
    void entry() { cout << "FunctionMode::entry" << endl; }
    void exit() { cout << "FunctionMode::exit" << endl; }
    void init() { setState<F1Mode>(); } // initial transition
};

SUBSTATE(F1Mode, FunctionMode) {
    STATE(F1Mode)
    virtual void evF1() {} // make the event an internal transition (by swallowing it)
private:
    void entry() { cout << "F1Mode::entry" << endl; }
    void exit() { cout << "F1Mode::exit" << endl; }
};

SUBSTATE(F2Mode, FunctionMode) {
    STATE(F2Mode)
    virtual void evF2() {} // make the event an internal transition (by swallowing it)
private:
    void entry() { cout << "F2Mode::entry" << endl; }
    void exit() { cout << "F2Mode::exit" << endl; }
};

} // namespace FunctionMode

int main() {

    Macho::Machine<FunctionMode::Top> sm;
    // Now the machine is already in F1Mode.

    // Macho has 2 methods for synchronous event dispatching:
    // First method:
    sm->evF1(); // <= this one will be swallowed by F1Mode::evF1()
    // Second method:
    sm.dispatch(Event(&FunctionMode::Top::evF2));

    return 0;
}

运行它,输出是:

FunctionMode::entry
F1Mode::entry
F1Mode::exit
F2Mode::entry
F2Mode::exit
FunctionMode::exit

这表明转换是内部的。

在我看来,干净、简单和紧凑的代码:-)

[EDIT1] 第一个版本的代码没有执行初始转换 FunctionMode -> F1Mode。现在可以了。

关于c++ - Boost Statechart - 本地转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11362065/

相关文章:

c++ - 我如何以编程方式找出 IIS 服务器有多少资源以及每个资源的流量..等等

c++ - 使用 Boost Graph 库查找连通分量,顶点和边类型为 boost::listS

c++ - 将 Boost.Spirit.X3 解析器拆分为多个 TU

c++ - 崩溃 : Segmentation fault: Boost serialization loading - calling constructor with null

c++ - Boost.Python 是否需要其他 boost 库的绑定(bind)代码?

c++ - 潜在的内存泄漏?

c++ - 使用 libsox 将音频转换为 FLAC

c++ - 基类的虚拟析构函数 c++