Как я могу получить boost :: function (или другую обертку универсальной функции), которая возвращает себя?

Недавно я был очарован простотой модели параллелизма, основанной на актерах, и играю с идеями для реализации некоторых ее частей в C ++. Кроме того, мне также нравится идея реализации конечного автомата в виде набора функций, представляющих состояния, где переходы выполняются путем вызова хвоста от одной функции к другой.

Я хотел бы попробовать нечто подобное в C ++. Но наивная реализация этого, вероятно, натолкнется на тот факт, что хвостовой вызов в моем компиляторе (GCC 4.1 с -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(...) может создавать), а не только указатели функций.

НОТА: я использую boost::bind, boost::function, boost::ref вместо их std:: коллеги, потому что я застрял с использованием GCC 4.1, который не поддерживает C ++ 11. Решения, действительные в C ++ 03, приветствуются ;-).

6

Решение

Вы не можете напрямую сделать это через typedef, но вы можете обернуть 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){}
};

Живой пример.

5

Другие решения

Это невозможно. Тип будет бесконечным, и проблема идентична той, с которой вы столкнетесь при определении указателя на функцию, которая возвращает себя. Единственный способ сделать это вручную написать свой собственный объект функции с помощью оператора (), это может вернуть *thisи цепь() звонки. Вы также можете использовать цепочку операторов другими способами, как вы можете видеть в std::cout,

3

Ты не можешь. Проблема в том, что определение возвращаемого типа должно быть рекурсивным, а это невозможно.

0
По вопросам рекламы [email protected]