C ++ 11 — Как я могу сделать автомат / кодирование конечного автомата в C ++?

Я использовал его на другом языке программирования, и это очень полезно.

Я не могу найти ничего об этом для C ++.

Давайте, например, возьмем следующий код:

void change();

enum
{
end = 0,
gmx
}

int
gExitType;

int main()
{
gExitType = end;
SetTimer(&change, 10000, 0);
return 0;
}

void ApplicationExit()
{
switch (gExitType)
{
case end:
printf("This application was ended by the server");
case gmx:
printf("This application was ended by the timer");
}
::exit(0);
}

void change()
{
gExitType = gmx;
ApplicationExit();
}

Это как то, как мы бы это делали в C ++, но при использовании конечного автомата / автоматов я мог бы сделать что-то подобное на другом языке:

void change();

int main()
{
state exitType:end;
SetTimer(&change, 10000, 0);
return 0;
}

void ApplicationExit() <exitType:end>
{
printf("This application was ended by the server");
}

void ApplicationExit() <exitType:gmx>
{
printf("This application ended by the timer");
}

void change()
{
state exitType:gmx;
ApplicationExit();
}

По моему мнению, это действительно элегантный способ достижения цели.
Как бы я сделал это в C ++? Этот код, кажется, не работает (очевидно, поскольку я не могу найти ничего автоматов, связанных с C ++)

Чтобы уточнить мое мнение:

Так каковы преимущества использования этой техники? Ну, как вы можете ясно видеть, код меньше; Конечно, я добавил перечисление в первую версию, чтобы сделать примеры более похожими, но функции ApplicationExit явно меньше. Это также намного более явно — вам не нужны большие операторы switch в функциях для определения того, что происходит, если вы хотите, вы можете поместить разные ApplicationExits в разные файлы для независимой обработки разных наборов кода. Он также использует меньше глобальных переменных.

3

Решение

В этом конкретном примере вы можете использовать объекты и полиморфизм для представления различных состояний. Например:

class StateObject
{
public:
virtual void action(void) = 0;
};

class EndedBy : public StateObject
{
private:
const char *const reason;

public:
EndedBy( const char *const reason_ ) : reason( reason_ ) { }
virtual void action(void)
{
puts(reason);
}
};

EndedBy EndedByServer("This application was ended by the server");
EndedBy EndedByTimer ("This application ended by the timer");

StateObject *state = &EndedByServer;

void change()
{
state = &EndedByTimer;
}

void ApplicationExit()
{
state->action();
::exit(0);
}

int main()
{
SetTimer(&change, 10000, 0);

// whatever stuff here...
// presumably eventually causes ApplicationExit() to get called before return 0;

return 0;
}

Тем не менее, это не отличный дизайн, и это не FSM в общем смысле. Но это осуществит вашу насущную потребность.

Вы можете посмотреть шаблон состояния (одна ссылка: http://en.wikipedia.org/wiki/State_pattern ) для более общего рассмотрения этого паттерна.

Однако основная идея заключается в том, что каждое состояние является подклассом некоторого общего класса «состояний», и вы можете использовать полиморфизм для определения различных действий и поведений, представленных каждым состоянием. Указатель на общий базовый класс «state» отслеживает состояние, в котором вы находитесь в данный момент.

Объекты состояния могут быть разных типов или, как в моем примере выше, разные экземпляры одного и того же объекта, настроенные по-разному, или смесь.

2

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

Существуют библиотеки C ++, такие как Boost.statechart, которые специально пытаются обеспечить расширенную поддержку конечных автоматов кодирования:
http://www.boost.org/doc/libs/1_54_0/libs/statechart/doc/tutorial.html

Помимо этого, один очень элегантный способ кодирования определенных типов конечных автоматов состоит в том, чтобы определить их как программу:
http://c2.com/cgi/wiki?CoRoutine
http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/

Сопрограммы напрямую не поддерживаются в C ++, но есть два возможных подхода к
реализуя их:

1) Использование техники, аналогичной реализации устройства Даффа, подробно объяснено здесь:
http://blog.think-async.com/search/label/coroutines
Это очень похоже на то, как работают итераторы C #, например, и одно ограничение состоит в том, что получение сопрограммы может быть сделано только из самой верхней функции в стеке вызовов сопрограммы. OTOH, преимущество этого метода в том, что для каждого экземпляра сопрограммы требуется очень мало памяти.

2) Выделение отдельного стека и регистрация места для каждой сопрограммы.
По сути, это делает сопрограмму полноценным потоком выполнения с той лишь разницей, что пользователь несет полную ответственность за планирование потоков (также известное как совместная многозадачность).

Портативная реализация доступна от boost:
http://www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html

3

Вы можете использовать специализацию значений шаблона над int, чтобы достичь почти того, что вы хотите.

(Извините, я на своем планшете, поэтому не могу привести пример, обновлю в воскресенье)

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