4

我正在尝试学习 boost::statechart。

我想制作一个加载文件的小应用程序。

//  --------------------------------
// |                                |
// |           O     Project        |
// |           |                    |
// |           v                    |
// |  ----------------------------  |
// | |                            | |
// | |         Unloaded           | |
// |  ----------------------------  |
// |  |              ^              |
// |  | EvLoad       | EvUnload     |<-----O
// |  v              |              |
// |  ----------------------------  |
// | |                            | |
// | |         Loaded             | |
// |  ----------------------------  |
// |           |   ^                |
// |           |   | EvLoad         |
// |           -----                |
//  --------------------------------

但是我如何将参数传输到状态,例如文件名?如果我将文件名存储在 EvLoad 中,我可以轻松访问它以进行状态反应

struct Loaded : sc::simple_state< Loaded, Project>
{
    typedef sc::custom_reaction< EvLoad > reactions;
    sc::result react( const EvLoad & e )
    {
        //load file e.path()
        ...
        return discard_event();
    }
}

但是当我处于 Unloaded 状态时,我正在调用 Loaded 的构造函数,我无法将参数传递给它。我想出的唯一解决方法是在转换之前重新发布事件,但这对我来说看起来有点脏。

struct Unloaded : sc::simple_state< Unloaded, Project >
{
    typedef sc::custom_reaction< EvLoad > reactions;
     sc::result react( const EvLoad & e )
     {
         post_event( e ); //workaround to pass the event to the loaded state
         return transit<Loaded>();
     }
};

有更好的选择吗?

4

2 回答 2

10

我们使用 triggering_event 方法来拉取触发事件,然后将数据作为成员变量附加到触发事件。它节省了大量的编码工作,并使我们不必生成自定义反应或将转换变量附加到状态图(我见过的两种常见方法)。

于 2012-03-30T13:00:23.557 回答
4

在我在下面输入我的建议后,我在谷歌搜索期间找到了这个链接,这表明你已经在做的事情(发布内部事件或使用数据重新发布事件)就是这样做的方法。那是来自 Boost statechart 的作者,那么谁来争论呢?:)

我的替代建议是,如果您的任何数据一旦加载就存在于“项目”级别,那么加载的文件名将成为 FSM 状态信息的一部分,处于“项目”级别而不是“加载”状态。

您可以使文件名成为 EvLoad 事件/构造函数的参数,对转换执行自定义操作并存储在“项目”上下文中加载的文件名。我认为这更适合状态图概念。

所以像这样的东西(虽然我没有测试过),显然你会清理它以比这更好地封装成员:

struct EvLoad: sc::event<EvLoad>
{
    std::string filename;

    EvLoad(const std::string& fn) : filename(fn) {}
};

struct EvUnload: sc::event<EvUnload>

struct Project : sc::state_machine<Project, Unloaded>
{
    std::string filename;

    void LoadFile(const EvLoad& e)
    {
        // Load file
        filename = e.filename;
    }

    void UnloadFile(const EvUnload& e)
    {
        filename.clear();
        // Unload file data
    }
};

struct Unloaded : sc::simple_state<Unloaded, Project>
{
    typedef sc::transition<EvLoad, Loaded, Project, &Project::LoadFile> reactions; 
};

struct Loaded : sc::simple_state<Loaded, Project>
{
    typdef mpl::list<
        sc::transition<EvLoad, Loaded, Project, &Project::LoadFile>,
        sc::transition<EvUnload, Unloaded>
    > reactions;
};

当你去加载一个文件驱动状态机时调用诸如 project.process_event(EvLoad(filename));

或者,您可以将文件名存储在“项目”状态中,然后使用 context().filename 从 Loaded 状态访问它。

于 2011-08-06T21:54:23.947 回答