среда, 15 июня 2011 г.

Список состояний конечного автомата

Подсмотрел у Алексея Пахунова
Все описанное относится к конечным автоматам, но никто не мешает применять эту технику и других подходящих ситуациях.
Лично мне это очень сильно напомнило подходы из BOOST_PP, но есть случаи, когда стоит "повоевать" и вручную...

Есть простой и довольно удобный способ держать список состояний/событий конечного автомата в одном месте. А то обычно они норовят расползтись по разным углам: enum, объявляющий соответствующие константы, массив имен состояний для отладки, большой switch, выбирающий что делать, в зависимости от состояния…
Делается примерно следующее (препроцессорная магия):
#define FOR_ALL_STATES(Action) \
    Action(StateInitial) \
    Action(StateInitializing) \
    Action(StateReady) \
    Action(StateTerminating)

После этого можно сами объявлять константы:
#define DEFINE_ENUM(Name) Name,

enum States {
    FOR_ALL_STATES(DEFINE_ENUM)
};

#undef DEFINE_ENUM

А можно – объявить прототипы функций-обработчиков для каждого из состояний:
#define DEFINE_HANDLER(Name) \
    States On ##Name(Events Event);

FOR_ALL_STATES(DEFINE_HANDLER)

#undef DEFINE_HANDLER

Или массив имен состояний, удобный для отладки:

#define DEFINE_NAME(Name) #Name,

static const char* StateNames[] = {
    FOR_ALL_STATES(DEFINE_NAME)
};

#undef DEFINE_NAME

Комментариев нет: