我正在尝试学习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>();
}
};
有更好的选择吗?
答案 0 :(得分:9)
我们使用triggering_event方法来拉取触发事件,然后将数据作为成员变量附加到触发事件。它节省了大量的编码工作,使我们不必生成自定义反应或将转换变量附加到状态图(我见过的两种常见方法)。
答案 1 :(得分:4)
我在下面输入我的建议后,在Google搜索过程中找到了this link,其中说明您正在做的事情(发布内部事件或将事件与数据一起重新发布)是可行的方法它。那是来自Boost状态图的作者,那么谁来争论呢? :)
我的替代建议是,如果您的任何数据一旦加载就存在于“项目”级别,那么加载的文件名将成为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))之类的调用来加载文件驱动器状态机时;
或者,您可以将文件名存储在“Project”状态,并使用来自Loaded状态的context()。filename访问它。