我最近对Erlang基于actor的并发模型的简单性感到迷恋,并且正在尝试用C ++实现它的某些部分。在这些方面,我也喜欢将有限状态机实现为表示状态的函数集合的想法,其中通过从一个函数到下一个函数的尾调用来进行转换。
我想在C ++中尝试类似的东西。但是这种天真的实现可能会遇到这样的事实:我的编译器中的尾部调用(带有-O0
的GCC 4.1)最终会导致堆栈溢出。所以相反,我想做的是让每个状态/函数返回一个仿函数(下一个要进入的状态),并且有一个底层循环,它只是顺序调用一个仿函数,然后调用这样返回的仿函数,然后调用仿函数因此返回,等等:
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(...)
可能会创建),而不仅仅是函数指针。
注意:我正在使用boost::bind
,boost::function
,boost::ref
而不是std::
对应者,因为我使用的是GCC 4.1 ,它不支持C ++ 11。感谢在C ++ 03中有效的解决方案; - )。
答案 0 :(得分:5)
你不能通过typedef
直接执行此操作,但是你可以将boost::function
包装在struct / class中(感谢@R. Martinho Fernandes让我有这种洞察力):< / p>
#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){}
};
答案 1 :(得分:3)
这是不可能的。类型将是无限的,并且问题与定义返回自身的函数指针时遇到的问题相同。执行此操作的唯一方法是使用operator()手动编写自己的函数对象,这可以返回*this
和链()
调用。您也可以通过其他方式使用操作员链接,就像您在std::cout
中看到的那样。
答案 2 :(得分:0)
你做不到。问题是返回类型的定义必须是递归的,这是不可能的。