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 メソッドを使用してトリガー イベントを取得し、データをメンバー変数としてトリガー イベントにアタッチします。これにより、多くのコーディング作業が節約され、カスタム リアクションを生成したり、遷移変数をステートチャートに追加したりする必要がなくなります (私が見た 2 つの一般的なアプローチ)。

于 2012-03-30T13:00:23.557 に答える
4

以下に私の提案を入力した後、Google検索中にこのリンクを見つけました。これは、あなたがすでに行っていること(内部イベントの投稿またはデータを使用したイベントの再投稿)がそれを行う方法であるということです。そして、それは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));などの呼び出しを使用してステートマシンをロードします。

または、ファイル名を「プロジェクト」状態で保存し、ロード状態からcontext()。filenameを使用してアクセスすることもできます。

于 2011-08-06T21:54:23.947 に答える