Важное примечание: eUML требует компилятора, поддерживающего Boost. Типа того. Полный eUML имеет экспериментальный статус (но не только переходная таблица написана с использованием eUML), потому что некоторые компиляторы начнут ломаться, когда государственная машина становится слишком большой (обычно, когда вы пишете огромные действия).
Предыдущие интерфейсы просты в написании, но все еще вызывают много шума, в основном типов MPL, поэтому было бы неплохо писать код, похожий на C++ (с языком действия C++) непосредственно внутри таблицы перехода, как это любят делать разработчики UML на своих диаграммах состояния машины. Если бы это было функциональное программирование, это было бы еще лучше. Для этого и существует eUML.
eUML - это рост. Прото и буст. Тип основанного на компиляции времени домена конкретного встроенного языка. В нем содержатся грамматики, позволяющие определять действия/охраны непосредственно внутри таблицы перехода или входа/выхода в определении состояния. Существуют грамматики действий, стражи, флаги, атрибуты, отложенные события, начальные состояния.
Он также опирается на рост. Typeof как обертка вокруг новой функции decltype C++0x, чтобы обеспечить оценку всех грамматик по времени компиляции. К сожалению, все базовые библиотеки Boost не поддерживают Typeof, поэтому на данный момент вам понадобится компилятор, в котором поддерживается Typeof (например, VC9-10, g++ > = 4.3).
Примеры будут приведены в следующих пунктах. Вы должны включить основные функции eUML:
#include <msm/front/euml/euml.hpp>
Чтобы добавить поддержку STL (при возможной стоимости более длительного времени компиляции), включите:
#include <msm/front/euml/stl.hpp>
eUML определяется в пространстве имен msm::front::euml.
Transition table
Переход можно определить, используя eUML как:
source + event [guard] / action == target
или как
target == source + event [guard] / action
Первая версия выглядит как нарисованный переход на диаграмме, вторая кажется естественной для разработчика C++.
Простая таблица переходов, написанная с помощью интерфейса functor , теперь может быть написана следующим образом:
BOOST_MSM_EUML_TRANSITION_TABLE((
Stopped + play [some_guard] / (some_action , start_playback) == Playing ,
Stopped + open_close/ open_drawer == Open ,
Stopped + stop == Stopped ,
Open + open_close / close_drawer == Empty ,
Empty + open_close / open_drawer == Open ,
Empty + cd_detected [good_disk_format] / store_cd_info == Stopped
),transition_table)
Или, используя альтернативное обозначение, это может быть:
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play [some_guard] / (some_action , start_playback) ,
Open == Stopped + open_close/ open_drawer ,
Stopped == Stopped + stop ,
Empty == Open + open_close / close_drawer ,
Open == Empty + open_close / open_drawer ,
Stopped == Empty + cd_detected [good_disk_format] / store_cd_info
),transition_table)
Переходная таблица теперь выглядит как список правил с небольшим шумом.
UML определяет защитные механизмы между “[ ]” и действиями после a“/”, поэтому выбранный синтаксис уже более удобочитаем для дизайнеров UML. UML также позволяет дизайнерам определять несколько действий последовательно (наша предыдущая ActionSequence_), разделенных запятой. Первый переход делает именно это: два действия, разделенные запятой и заключенные в скобки, чтобы уважать приоритет оператора C++.
Если вам кажется, что это будет стоить вам производительности во время выполнения, не волнуйтесь, eUML основан на типе (или деклапте), который оценивает параметры только для BOOST_MSM_EUML_TRANSITION_TABLE, и не происходит затрат времени выполнения. Фактически, eUML представляет собой только слой метапрограммирования поверх «стандартного» метапрограммирования MSM, и этот первый слой генерирует ранее введенный functor front-end.
UML также позволяет дизайнерам определять более сложные защитные элементы, такие как [good_disk_format && (some_condition | | some_other_condition)]. Это было возможно с нашими ранее определенными функторами, но с использованием сложного синтаксиса шаблона. Этот синтаксис теперь возможен точно так же, как и записанный, что означает отсутствие синтаксического шума вообще.
A simple example: rewriting only our transition table
В качестве введения в eUML мы перепишем таблицу перехода нашего учебника с использованием eUML. Для этого потребуется два-три изменения в зависимости от компилятора:
события должны наследоваться от msm::front::euml::euml_event< event_name >
состояния должны наследоваться от msm::front::euml:::euml_state< state_name >
с VC, состояния должны быть объявлены перед front-end
Теперь мы можем написать таблицу перехода, как только что показано, используя BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE Вместо BOOST_MSM_EUML_TRANSITION_TABLE. Реализация довольно проста. Единственным необходимым дополнением является необходимость объявить переменную для каждого состояния или добавить в таблицу переходов паренсы (звонок разработчика по умолчанию).
// front-end like always
struct sub_front_end : public boost::msm::front::state_machine_def<sub_front_end>
{
...
};
// back-end like always
typedef boost::msm::back::state_machine<sub_front_end> sub_back_end;
sub_back_end const sub; // sub can be used in a transition table.
К сожалению, есть ошибка с VC, которая время от времени появляется и вызывает переполнение стека. Если вы получите предупреждение о том, что программа рекурсивна на всех путях, вернитесь к стандартному eUML или другому интерфейсу, поскольку Microsoft, похоже, не намерена его исправлять.
Теперь у нас есть новая, более читаемая таблица переходов с небольшими изменениями в нашем примере. EUML может сделать гораздо больше, поэтому, пожалуйста, следуйте руководству.
Defining events, actions and states with entry/exit actions
Events
События должны быть прото-включены. Для этого они должны наследовать от прототерминала (euml_event). eUML также предоставляет макрос, чтобы сделать это проще:
BOOST_MSM_EUML_EVENT(play)
Этот тип событий и экземпляр этого типа называется play, который теперь готов к использованию в поведении состояния или перехода.
Существует второй макрос, BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, который принимает в качестве второго параметра атрибуты, которые будет содержать событие, используя синтаксис атрибутов .
Примечание : поскольку у нас теперь есть события, определенные как экземпляры, а не просто типы, мы все еще можем обрабатывать событие, создавая его на лету, например: fsm.process_event(play()); или нам нужно написать: fsm.process_event(play);
Ответ заключается в том, что вы можете сделать оба. Второй легче, но в отличие от других интерфейсов, второй использует определенный оператор (), который создает событие на лету.
Actions
Действия (возвращение пустоты) и предохранители (возвращение функтора) определяются как предыдущие функторы, с той разницей, что они также должны быть прото-включены. Это может быть сделано путем наследования от euml_action< functor-name >. eUML также предоставляет макрос:
Как и для событий, этот макрос объявляет тип функтора и пример для использования в поведении переходного или состояния.
Можно использовать одну и ту же грамматику действий из таблицы перехода для определения поведения входа и выхода состояния. Таким образом, (действие1, действие2) является действительным поведением входа или выхода, выполняющим оба действия в свою очередь.
Функторы состояния имеют несколько иную подпись, поскольку нет состояния источника и целевого состояния, а только текущее состояние (действия входа / выхода являются независимыми от перехода), например:
Также возможно повторное использование функторов из интерфейса функтора. Синтаксис, однако, немного менее удобен, так как нам нужно притвориться, что мы создаем его на лету. Например:
Есть и макрос для государств. Этот макрос имеет 2 аргумента, сначала выражение, определяющее состояние, затем название государства (инстанции):
BOOST_MSM_EUML_STATE((),Paused)
Это определяет простое состояние без действия входа или выхода. Вы можете обеспечить в параметре выражения поведение состояния (вход и выход) с помощью грамматики действия, как в таблице перехода:
Это означает, что Пустота определяется как состояние с входным действием, состоящим из двух поддействий, Пустота_Вход и Пустота_Вход (замкнутый внутри скобки), и выходным действием, Пустота_Выход.
Существует несколько possibilitites для синтаксиса выражения :
(): состояние без действия входа или выхода.
(Expr1): состояние с входом, но без выхода.
(Expr1,Expr2): состояние с действием входа и выхода.
(Expr1,Expr2,Attributes): состояние с действием входа и выхода, определяющее некоторые атрибуты (читайте дальше).
(Expr1,Expr2,Attributes,Configure): состояние с действием входа и выхода, определение некоторых атрибутов (читай дальше) и флагов (стандартные флаги MSM) или отложенных событий (стандартные отложенные события MSM).
(Expr1,Expr2,Attributes,Configure,Base): состояние с действием входа и выхода, определение некоторых атрибутов (читай дальше), флаги и отложенные события (простые отложенные события msm) и базовое состояние без по умолчанию (как определено в стандарте MSM).
также определяется действие no_action, которое не делает ничего, кроме того, что является заполнителем (необходимым, например, в качестве действия входа, если у нас нет входа, кроме выхода). Expr1 и Expr2 представляют собой последовательность действий, подчиняющихся той же грамматике действий, что и в таблице переходов (после символа “/”).
Макро BOOST_MSM_EUML_STATE позволяет определить наиболее распространенные состояния, но иногда вам потребуется больше, например, обеспечить в ваших состояниях некоторое особое поведение. В этом случае придется делать макрозадание вручную, что не очень сложно. Государство должно будет наследовать от msm::front::state<>, как и любое государство, и от euml_state, чтобы иметь прото-возможность. Затем вам нужно будет указать пример для использования в таблице перехода. Например:
struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
{
void activate_empty() {std::cout << "switching to Empty " << std::endl;}
template <class Event,class Fsm>
void on_entry(Event const& evt,Fsm&fsm){...}
template <class Event,class Fsm>
void on_exit(Event const& evt,Fsm&fsm){...}
};
//instance for use in the transition table
Empty_impl const Empty;
Обратите внимание, что мы определили метод под названием «Active_empty». Мы хотели бы назвать это поведением. Это можно сделать с помощью BOOST_. MSM_EUML_METHOD макрос.
Первый параметр — это название основного функтора, которое вы можете использовать с фронтальным функтором, второй — название метода состояния, третий — функция, генерируемая eUML, четвертый и пятый — возвращаемое значение при использовании внутри перехода или поведения состояния. Теперь вы можете использовать это в переходе:
Empty == Open + open_close / (close_drawer,activate_empty_(target_))
Wrapping up a simple state machine and first complete examples
Вы можете повторно использовать метод определения состояния машины из стандартного интерфейса и просто заменить таблицу перехода на эту новую. Вы также можете использовать eUML для определения машины состояния «на лету» (если, например, вам нужно предоставить on_entry/on_exit для этой машины состояния в качестве функтора). Для этого существует также макрос BOOST_MSM_EUML_DECLARE_STATE_MACHINE, который имеет 2 аргумента, выражение, описывающее машину состояния и название машины состояния. Выражение имеет до 8 аргументов:
(Stt, Init): простейшая машина состояний, где определены только таблица переходов и начальное состояние(ы).
(Stt, Init, Expr1): машина состояния, в которой определены таблица переходов, начальное состояние и действие входа.
(Stt, Init, Expr1, Expr2): машина состояния, в которой определены переходная таблица, начальное состояние, действия входа и выхода.
(Stt, Init, Expr1, Expr2, Атрибуты): машина состояния, в которой определены переходная таблица, начальное состояние, действия входа и выхода. Кроме того, добавлены некоторые атрибуты (читайте дальше).
(Stt, Init, Expr1, Expr2, Attributes, Configure): машина состояния, в которой определены переходная таблица, начальное состояние, действия входа и выхода. Кроме того, добавлены некоторые атрибуты (читайте дальше), флаги, отложенные события и возможности конфигурации (без очереди сообщений / без исключения).
(Stt, Init, Expr1, Expr2, Attributes, Flags, Deferred, Base): машина состояния, в которой определены переходная таблица, начальное состояние, действия входа и выхода. Кроме того, добавлены атрибуты (читайте дальше), флаги, отложенные события и возможности конфигурации (без очереди сообщений / без исключения) и определено базовое состояние без по умолчанию (см. заднее описание ).
Например, машина минимального состояния может быть определена как:
Пожалуйста, взгляните на учебник игрока, написанный с использованием первого синтаксиса eUML и второго синтаксиса . Макро BOOST_MSM_EUML_DECLARE_ATTRIBUTE, к которому мы вскоре вернемся, объявляет атрибуты, данные типу eUML (состояние или событие), используя синтаксис атрибутов .
Defining a submachine
Определение подмашины (см. tutorial) с другими передними концами просто означает использование состояния, которое является машиной состояния в таблице перехода другой машины состояния. То же самое касается eUML. Нужно только определить вторую машину состояния и сослаться на нее в таблице перехода содержащей машины состояния.
В отличие от макросов определения состояния или события, BOOST_MSM_EUML_DECLARE_STATE_MACHINE определяет тип, а не экземпляр, потому что тип - это то, что требуется бэкэнду. Это означает, что вам нужно будет заявить о себе, чтобы ссылаться на свою подмашину в другую государственную машину, например:
Теперь мы можем использовать этот экземпляр внутри таблицы перехода содержащейся машины состояний:
Paused == Playing + pause / pause_playback
Attributes / Function call
Теперь мы хотим сделать нашу грамматику более полезной. Очень часто требуются только очень простые методы действия, например ++Counter или Counter > 5, где Counter обычно определяется как некоторый атрибут класса, содержащего машину состояния. Кажется пустой тратой писать функтор для такого простого действия. Кроме того, состояния внутри МСМ также являются классами, поэтому они могут иметь атрибуты, и мы также хотели бы предоставить им атрибуты.
Если вы посмотрите на наши примеры, используя синтаксисы first и second, вы найдете BOOST_MSM_EUML_DECLARE_ATTRIBUTE и макрос BOOST_MSM_EUML_ATTRIBUTES. Первый из них определяет возможные атрибуты:
Объявляют два атрибута: cd_name типа std::string и cd_type типа DiskTypeEnum. Эти атрибуты не являются частью какого-либо события или состояния в частности, мы просто объявили имя и тип. Теперь мы можем добавить атрибуты к нашему cd_обнаруженному событию, используя второй:
Это объявляет список атрибутов, который еще не связан ни с чем конкретным. Он может быть прикреплен к государству или событию. Например, если мы хотим, чтобы событие cd_detected имело эти определенные атрибуты, мы пишем:
Хорошо, отлично, теперь у нас есть способ добавить атрибуты к классу, что мы могли бы сделать легче, так в чем смысл? Дело в том, что теперь мы можем ссылаться на эти атрибуты непосредственно, во время компиляции, в таблице перехода. Например, в примере вы найдете этот переход:
Прочитайте event_(cd_type) как event_->cd_type с event_типом, общим для событий, каким бы ни было конкретное событие (в данном конкретном случае оно оказывается cd_обнаруженным, как показывает переход).
Основным преимуществом этой функции является то, что вам не нужно определять новый функтор, и вам не нужно заглядывать внутрь функтора, чтобы знать, что он делает.
МСМ предоставляет более общие объекты для типов государственных машин:
событие_: используется внутри любого действия, событие, запускающее переход
state_: используется внутри действия входа и выхода, состояние входа / выхода
source_: используется внутри переходного действия, состояние источника
target_: используется в переходном действии, целевое состояние
fsm_: используется в любом действии, (самый низкий уровень) состояние машины обрабатывает переход
Эти помощники могут использоваться двумя различными способами:
helper(attribute_name) возвращает атрибут с именемtribute_name
помощник возвращает состояние/тип события.
Вторая форма полезна, если вы хотите предоставить своим штатам свои собственные методы, которые вы также хотите использовать внутри таблицы перехода. В руководстве выше мы предоставляем Empty метод активации_empty. Мы хотели бы создать функтор eUML и назвать его изнутри таблицы переходов. Это делается с помощью макросов MSM_EUML_METHOD/MSM_EUML_FUNCTION. Первый создает функтор к методу, второй к свободной функции. В учебнике мы пишем:
Первым параметром является название функтора, для использования с фронтендом функтора. Второе — название метода вызова. Третье - это название функции для использования с eUML, четвертое - тип возврата функции, если используется в контексте действия перехода, пятое - тип результата, если используется в контексте действия входа / выхода состояния (обычно четвертое и пятое - одно и то же). Теперь у нас есть новая функция eUML, называемая методом «что-то», и это «что-то» является одним из пяти ранее показанных общих помощников. Теперь мы можем использовать это в переходном периоде, например:
Empty == Open + open_close / (close_drawer,activate_empty_(target_))
Действие теперь определяется как последовательность из двух действий: close_drawer и activate_empty, которая вызывается на саму цель. Цель, являющаяся Пустой (состояние, определенное слева), на самом деле будет называться Пустой::activate_empty(). Этот метод также может иметь (или несколько) аргументов (аргументов), например событие, которое мы можем назвать активированным_пустым_(target_, event_).
Больше примеров можно найти в стресс-тесте компилятора terrible, примере timer или в iPodSearch с eUML (для String_ и более).
Orthogonal regions, flags, event deferring
Определение ортогональных регионов действительно означает предоставление большего количества исходных состояний. Чтобы добавить больше начальных состояний, “ Shift left” некоторые, например, если бы у нас было другое начальное состояние под названием AllOk :
Вы помните из подписей BOOST_MSM_EUML_STATE и BOOST_MSM_EUML_DECLARE_STATE_MACHINE, что сразу после атрибутов мы можем определить флаги, как в базовом интерфейсе MSM. Для этого у нас есть еще одна грамматика «сдвиг-лево», например:
Теперь мы определили, что Paused получит два флага, PlayingPaused и CDLoaded, с другим макросом:
BOOST_MSM_EUML_FLAG(CDLoaded)
Это соответствует следующему базовому определению интерфейса Paused:
struct Paused : public msm::front::state<>
{
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
};
Под капотом вы получаете mpl::vector2.
Примечание : При использовании версии выражения BOOST_MSM_EUML_STATE с 4 аргументами мы должны сообщить eUML, что нам не нужны атрибуты. Аналогично cout << endl, нам нужен синтаксис attributes_ << no_attributes_.
Флаг можно использовать с помощью метода is_flag_active государственной машины. Вы также можете использовать предоставленную функцию помощника is_flag_ (возврат кипения) для состояний и переходов. Например, в i Реализация под с eUML, вы найдете следующий переход:
Функция также имеет дополнительный второй параметр, который является машиной состояния, на которой функция называется. По умолчанию используется fsm_ (машина текущего состояния), но вы можете предоставить функтор, возвращающий ссылку на другую машину состояния.
eUML также поддерживает определение отложенных событий в определении состояния (государственной машины). Для этого можно использовать грамматику флага. Например:
BOOST_MSM_EUML_STATE((Empty_Entry,Empty_Exit, attributes_ << no_attributes_,
/* deferred */ configure_<< play ),Empty)
Сдвиг влево также отвечает за отсрочку событий. Сдвиг внутри конфигурируемого флага и государство получит флаг, сдвинет событие и получит отложенное событие. Это заменяет основное определение интерфейса:
typedef mpl::vector<play> deferred_events;
В этом руководстве игрок определяет вторую ортогональную область с AllOk в качестве начального состояния. Состояния Empty и Open также откладывают событие play. Open, Stopped и Pause также поддерживают флаг CDLoaded Используя тот же левый сдвиг в configure_.
В передней части функтора у нас также была возможность отложить событие внутри перехода, что делает возможным условное отсрочку. Это также возможно с помощью eUML посредством использования порядка defer_, как показано в этом руководстве . Вы найдете следующий переход:
Open + play / defer_
Это внутренний переход. Игнорируйте это на данный момент. Интересно, что когда событие play будет запущено и Open будет активным, событие будет отложено. Теперь добавьте стражу и вы можете условно отложить мероприятие, например:
Open + play [ some_condition ] / defer_
Это похоже на то, что мы сделали с фронт-эндом. Это означает, что у нас одинаковые ограничения. Используя defer_ вместо государственной декларации, мы должны сообщить МСМ, что мы отложили события в этой государственной машине. Мы делаем это (опять же) с помощью заявления configure_ в определении машины состояния, в котором мы смещаем флаг конфигурации deferred_events:
Мы только что видели, как использовать конфигурацию для определения отложенных событий или флагов. Мы также можем использовать его для настройки нашей государственной машины, как это было с другими интерфейсами:
configure_ << no_исключение: отключение обработки исключений
configure_ << no_msg_queue деактивирует очередь сообщений
configure_ << deferred_events вручную позволяет отложить событие
Деактивация первых двух функций, а не активация третьей, если в этом нет необходимости, значительно повышает скорость передачи событий. Наш пример тестирования скорости с eUML делает это для лучшей производительности.
Важное примечание: Поскольку псевдосостояния выхода используют очередь сообщений для пересылки событий из подмашины, опция no_message_queue не может использоваться с машинами состояния, содержащими псевдосостояние выхода.
Completion / Anonymous transitions
Анонимные переходы (См. UML учебник ) представляют собой переходы без именованного события, которые, следовательно, запускаются сразу же, когда состояние источника становится активным, при условии, что это позволяет защита. Поскольку нет события, чтобы определить такой переход, просто опустить “ +” часть перехода (событие), например:
Как и оба других интерфейса, eUML поддерживает два способа определения внутренних переходов:
в таблице перехода машины состояния. В этом случае необходимо указать исходное состояние, событие, действия и предохранители, но не целевое состояние, которое eUML будет интерпретировать как внутренний переход, например, это определяет внутренний переход к Open, на событии open_close:
Open + open_close [internal_guard1] / internal_action1
Обратите внимание, что переход происходит из Open, поскольку мы уже находимся в контексте Open.
Реализация также показывает дополнительный бонус, предлагаемый для подмашин, которые могут иметь как стандартную таблицу переходов, так и внутреннюю таблицу переходов (которая имеет более высокий приоритет). Это упрощает задачу, если вы решили создать полноценную машину. Это также несколько быстрее, чем стандартная альтернатива, с добавлением ортогональных регионов, поскольку отправка событий, если она будет принята внутренней таблицей, не будет продолжаться в субрегионах. Это дает вам отправку O(1) вместо O(количество регионов).
Kleene(any) event)
Что касается фронт-энда функтора, то eUML поддерживает концепцию события любой , но бустер::любой не является приемлемым терминалом eUML. Если вам нужно событие any, используйте msm::front::euml::kleene, которое наследует импульс::any. Такой же переход, как и с повышением: любой будет:
State1 + kleene == State2
Other state types
Мы увидели функцию build_state, которая создает простое состояние. Кроме того, eUML предоставляет другие макросы государственного строительства для других типов государств:
BOOST_MSM_EUML_TERMINATE_STATE принимает те же аргументы, что и BOOST_MSM_EUML_STATE, и определяет конечное состояние.
BOOST_MSM_EUML_INTERRUPT_STATE Использует те же аргументы, что и BOOST_MSM_EUML_STATE, и определяет состояние прерывания. Однако аргумент выражения должен содержать в качестве первого элемента событие, заканчивающее прерывание, например: BOOST_MSM_EUML_INTERRUPT_STATE((end_error/*end interrupt event*/,ErrorMode_Entry,ErrorMode_Exit),ErrorMode)
BOOST_MSM_EUML_EXIT_STATE принимает те же аргументы, что и BOOST_MSM_EUML_STATE, и определяет псевдосостояние выхода. Однако аргумент выражения должен содержать в качестве первого элемента событие, распространяемое от точки выхода: BOOST_MSM_EUML_EXIT_STATE((событие6/*распространенное событие*/,PseudoExit1_Entry,PseudoExit1_Exit),PseudoExit1)
BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE определяет псевдосостояние входа. Требуется 3 параметра: введенный индекс области определяется как аргумент int, за которым следует выражение конфигурации, такое как BOOST_MSM_EUML_STATE и название государства, так что BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0 /*region index*/,). SubState2_Entry, SubState2_Exit,SubState2 определяет состояние входа в первый регион подмашины.
BOOST_MSM_EUML_ENTRY_STATE определяет псевдосостояние входа. Требуется 3 параметра: введенный индекс области определяется как аргумент int, за которым следует выражение конфигурации, такое как BOOST_MSM_EUML_STATE и название состояния, так что BOOST_MSM_EUML_ENTRY_STATE(0, (PseudoEntry1_Entry,PseudoEntry1_Exit),PseudoEntry1) определяет псевдосостояние входа в первую область подмашины.
Для использования этих состояний в таблице перехода eUML предлагает функции explicit_, exit_pt_ и entry_pt_. Например, прямой вход в субгосударственное подгосударство2 из SubFsm2 может быть:
if_then_else_(защита, действие, действие), где действие может быть последовательностью действия
if_then_(защита, действие), где действие может быть последовательностью действия
while_(защита, действие), где действие может быть последовательностью действия
do_while_(защита, действие), где действие может быть последовательностью действия
for_(действие, охрана, действие, действие), где действие может быть последовательностью действия
process_(some_event [, some state machine] [, some state machine] [, some state machine] [, some state machine] [, some state machine]) вызовет process_event (some_event) на текущей State machine или на прошедшем как 2-й, 3-й, 4-й, 5-й аргумент. Это позволяет отправлять события на несколько внешних машин
process_(event_): перерабатывает событие, вызвавшее переход
reprocess_(): то же, что и выше, но короче для записи
process2_(some_event, Value [, some state machine] [, some state machine] [, some state machine]) будет называться process_event (some_event(Value)) на текущей машине состояния или на той, которая прошла как 3-й, 4-й, 5-й аргумент
is_ flag_(some_flag[, some state machine]) будет называться is_flag_active на текущей государственной машине или на той, которая прошла как 2-й аргумент
Predicate_: Используется в алгоритмах STL. Обертывает унарные/двоичные функции, чтобы сделать их eUML-совместимыми, чтобы их можно было использовать в алгоритмах STL
(fsm.SongIndex > 0, call show_playing_song else) SongIndex=1; процесс EndPlay на fsm;}
Несколько примеров используют эти функции:
Пример iPod, представленный на BoostCon09 , был переписан с помощью eUML (слабые компиляторы, пожалуйста, перейдите на...)
Пример iPodSearch, также представленный на BoostCon09 , был переписан с помощью eUML. В этом примере вы также найдете некоторые примеры использования STL-функтора.
К сожалению, есть небольшой улов. Определение функтора с помощью MSM_EUML_METHOD или MSM_EUML_FUNCTION создает правильный функтор. Ваши собственные функторы eUML, написанные в начале этого раздела, также будут работать хорошо, , за исключением , на данный момент, с функциями while_, if_then_, if_then_else_.
Phoenix-like STL support
eUML поддерживает большинство операторов C++ (кроме адреса). Например, можно написать event_(some_attribute)++ или [source_(some_bool) && fsm_(some_other_bool)]. Но программисту нужно больше, чем операторам в его ежедневном программировании. Очевидно, что STL должен иметь. Поэтому eUML поставляется с большим количеством функторов, чтобы еще больше уменьшить потребность в собственных функторах для таблицы перехода. Практически для каждого алгоритма или метода контейнера STL определяется соответствующая функция eUML. Как и Boost.Phoenix, “.” And “->” объектов вызова заменяются парадигмой функционального программирования, например:
В двух словах, почти каждый метод или алгоритм STL соответствует соответствующему функтору, который затем может быть использован в таблице переходов или действиях состояния. В ссылке перечислены все функции eUML и лежащий в их основе функтор (так что эта возможность зарезервирована не только для eUML, но и для интерфейса на основе функтора). Файловая структура этой библиотеки, похожей на Феникс, соответствует структуре Boost. Феникс. Все функторы для алгоритмов STL можно найти в:
#include <msm/front/euml/algorithm.hpp>
Алгоритмы также разделены на подзаголовки, соответствующие структуре Феникса для простоты:
push_back_(fsm_(m_tgt_container),event_(m_song)): машина состояния имеет атрибут m_tgt_container типа std::vector и событие имеет атрибут m_song типа OneSong. Таким образом, строка выталкивает m_song в конце m_tgt_container
if_then_(state_(m_src_it) != end_(fsm_(m_src_container)), process2_(OneSong(),*(state_(m_src_it)++)) ): текущее состояние имеет атрибут m_src_it (итератор). Если этот итератор != fsm.m_src_container.end(), процесс OneSong на fsm, копия построена из state.m_src_it Что мы пост-прироста
Writing actions with Boost.Phoenix (in development)
Также можно писать действия, охранники, действия входа и выхода государства с помощью уменьшенного набора Boost. Возможности Феникса. Эта функция все еще находится в стадии разработки, поэтому вы можете получить здесь и там некоторый сюрприз. Однако простые случаи должны работать хорошо. Что не сработает, так это смешение функторов eUML и Phoenix. Написание охранников на одном языке и действий на другом - это нормально.
Phoenix также поддерживает больший синтаксис, чем когда-либо будет возможно с eUML, поэтому вы можете использовать только уменьшенный набор грамматики Феникса. Это связано с характером EUML. Определение таблицы переходов времени выполнения переводится на тип с использованием Boost. Типа того. В результате получается «нормальная» переходная таблица МСМ, выполненная из функторов. Поскольку C++ не позволяет смешивать конструкцию времени выполнения и времени компиляции, будет некоторый предел (попытка инстанцировать класс шаблонов MyTemplateClass где i - int даст вам идею). Это означает, что следующие действующие конструкции Феникса не будут работать:
буквы
указатели функций
bind
->*
MSM также предоставляет заполнители, которые имеют больше смысла в его контексте, чем arg1
_событие: событие, запускающее переход
_fsm: состояние машины, обрабатывающей событие
_source: состояние источника перехода
_target: целевое состояние перехода
_state: для действий входа/выхода государства, состояние входа/выхода
Будущие версии MSM будут лучше поддерживать Phoenix. Вы можете внести свой вклад, выяснив случаи, которые не работают, но должны, чтобы их можно было добавить.
Поддержка Phoenix по умолчанию не активируется. Чтобы активировать его, добавьте перед любым заголовком MSM: #define BOOST_MSM_EUML_PHOENIX_SUPPORT.
Простой пример показывает некоторые основные возможности.
Статья eUML раздела Meta State Machine (MSM) Chapter 3. Tutorial может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.