6

私は最近、Erlangのアクターベースの並行性モデルのシンプルさに夢中になり、C++でその一部を実装するためのアイデアを試しています。これらの方針に沿って、状態を表す関数のコレクションとして有限状態マシンを実装するというアイデアも気に入っています。ここでは、ある関数から次の関数への末尾呼び出しによって遷移が行われます。

C++で似たようなものを試してみたいです。しかし、これを単純に実装すると、コンパイラ(GCC 4.1 with -O0)で末尾呼び出しを行うと、最終的にスタックオーバーフローが発生する可能性があります。代わりに、私がやりたいのは、各状態/関数にファンクター(次に入る状態)を返し、ファンクターを順番に呼び出し、次に返されたファンクターを呼び出し、次にファンクターを呼び出す基になるループを作成することです。このように返されるなど。

typedef ... context_t;

// A statefunctor is a functor which takes a context_t and 
// returns a statefunctor
//
// FIXME: of course, this typedef won't compile.
typedef boost::function<statefunctor (context_t& )> statefunctor;

// NULL boost::function<> represents the exit condition.
static const statefunctor EXIT_FSM;

// primary loop which runs the FSM
void run_fsm(context_t& ctx, statefunctor initial_state)
{
    while (initial_state)
    {
        initial_state=initial_state(boost::ref(ctx));
    }
}

// states 'foo', 'bar', and 'baz';
statefunctor foo(context_t& ctx);
statefunctor bar(context_t& ctx, int inval);
statefunctor baz(context_t& ctx);

// State 'foo'
statefunctor foo(context_t& ctx)
{
    // act somehow on the external context
    int magic_number_1=ctx.get_magic_number();
    int magic_number_2=ctx.get_magic_number();

    // Always transition to 'bar'
    return boost::bind(&bar, _1, magic_number_1-magic_number_2);
}

// State 'bar'
statefunctor bar(context_t& ctx, int inval)
{
    inval+=ctx.get_magic_number(); // Act on external context somehow

    // transition to foo or baz
    if (inval>0) { return &foo; }
    else { return &baz; }
}

// State 'baz'
statefunctor baz(context_t& ctx)
{
    // Transition to foo or exit
    if (ctx.get_magic_number()==5) {return EXIT_FSM;}
    else {return &foo;}
}

int main()
{
    context_t ctx;
    // start the state machine in state 'foo'
    run_fsm(ctx, &foo);
}

だから、私の質問は、どのように定義するのstatefunctorですか?boost::bind(...)特に、関数ポインタだけでなく、任意のファンクタ(作成する可能性がある)を保持できるようにしたいです。

注: C ++11をサポートしていないGCC4.1を使用しているため、対応するものの代わりに、boost::bindを使用しています。C++03で有効なソリューションを歓迎します;-)。boost::functionboost::refstd::

4

3 に答える 3

5

を介してこれを直接行うことはできませんが、構造体/クラスでtypedefラップすることはできます( @R。Martinho Fernandesにこの洞察を与えてくれたことに感謝します):boost::function

#include <boost/function.hpp>

typedef int context_t;

struct statefunctor
  : boost::function<statefunctor(context_t&)>
{
  typedef boost::function<statefunctor(context_t&)> base_type;
  statefunctor() : base_type(){}
  template<class F>
  statefunctor(F f) : base_type(f){}
};

実例。

于 2012-09-06T16:58:06.407 に答える
3

これは不可能です。タイプは無限であり、問​​題は、それ自体を返す関数ポインターを定義するときに遭遇する問題と同じです。これを行う唯一の方法は、operator()を使用して独自の関数オブジェクトを手動で作成することです。これにより、、*thisおよびチェーン()呼び出しを返すことができます。で見ることができるように、他の方法で演算子チェーンを使用することもできますstd::cout

于 2012-09-06T16:38:27.670 に答える
0

それはいけません。問題は、返される型の定義が再帰的である必要があり、それが不可能であるということです。

于 2012-09-06T16:38:10.660 に答える