123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- <html><head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Functor front-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s02.html" title="Basic front-end"><link rel="next" href="ch03s04.html" title="eUML"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Functor front-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s02.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch03s04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Functor front-end"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1224"></a><span class="command"><strong><a name="functor-front-end"></a></strong></span>Functor front-end</h2></div></div></div><p>The functor front-end is the preferred front-end at the moment. It is more
- powerful than the standard front-end and has a more readable transition table.
- It also makes it easier to reuse parts of state machines. Like <span class="command"><strong><a class="command" href="ch03s04.html#eUML-front-end">eUML</a></strong></span>, it also comes with a good deal
- of predefined actions. Actually, eUML generates a functor front-end through
- Boost.Typeof and Boost.Proto so both offer the same functionality.</p><p>The rows which MSM offered in the previous front-end come in different
- flavors. We saw the a_row, g_row, _row, row, not counting internal rows. This is
- already much to know, so why define new rows? These types have some
- disadvantages: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>They are more typing and information than we would wish. This
- means syntactic noise and more to learn.</p></li><li class="listitem"><p>Function pointers are weird in C++.</p></li><li class="listitem"><p>The action/guard signature is limited and does not allow for more
- variations of parameters (source state, target state, current state
- machine, etc.)</p></li><li class="listitem"><p>It is not easy to reuse action code from a state machine to
- another.</p></li></ul></div><div class="sect2" title="Transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1248"></a> Transition table </h3></div></div></div><p>We can change the definition of the simple tutorial's transition table
- to:</p><pre class="programlisting">
- struct transition_table : mpl::vector<
- // Start Event Target Action Guard
- // +---------+------------+-----------+---------------------------+----------------------------+
- Row < Stopped , play , Playing , start_playback , none >,
- Row < Stopped , open_close , Open , open_drawer , none >,
- Row < Stopped , stop , Stopped , none , none >,
- // +---------+------------+-----------+---------------------------+----------------------------+
- Row < Open , open_close , Empty , close_drawer , none >,
- // +---------+------------+-----------+---------------------------+----------------------------+
- Row < Empty , open_close , Open , open_drawer , none >,
- Row < Empty , cd_detected, Stopped , store_cd_info , good_disk_format >,
- g_row< Empty , cd_detected, Playing , &player_::store_cd_info , &player_::auto_start >,
- // +---------+------------+-----------+---------------------------+----------------------------+
- Row < Playing , stop , Stopped , stop_playback , none >,
- Row < Playing , pause , Paused , pause_playback , none >,
- Row < Playing , open_close , Open , stop_and_open , none >,
- // +---------+------------+-----------+---------------------------+----------------------------+
- Row < Paused , end_pause , Playing , resume_playback , none >,
- Row < Paused , stop , Stopped , stop_playback , none >,
- Row < Paused , open_close , Open , stop_and_open , none >
- // +---------+------------+-----------+---------------------------+----------------------------+
- > {};
- </pre><p>Transitions are now of type "Row" with exactly 5 template arguments:
- source state, event, target state, action and guard. Wherever there is
- nothing (for example actions and guards), write "none". Actions and guards
- are no more methods but functors getting as arguments the detected event,
- the state machine, source and target state:</p><pre class="programlisting">struct store_cd_info
- {
- template <class Fsm,class Evt,class SourceState,class TargetState>
- void operator()(Evt const&, Fsm& fsm, SourceState&,TargetState& )
- {
- cout << "player::store_cd_info" << endl;
- fsm.process_event(play());
- }
- }; </pre><p>The advantage of functors compared to functions are that functors are
- generic and reusable. They also allow passing more parameters than just
- events. The guard functors are the same but have an operator() returning a
- bool.</p><p>It is also possible to mix rows from different front-ends. To show this, a
- g_row has been left in the transition table. <span class="underline">Note:</span> in case the action functor is used in the transition
- table of a state machine contained inside a top-level state machine, the
- “fsm” parameter refers to the lowest-level state machine (referencing this
- action), not the top-level one.</p><p>To illustrate the reusable point, MSM comes with a whole set of predefined
- functors. Please refer to eUML for the <a class="link" href="pt02.html#Reference-begin">full list</a>. For example, we are now going to replace the first
- action by an action sequence and the guard by a more complex functor.</p><p>We decide we now want to execute two actions in the first transition
- (Stopped -> Playing). We only need to change the action start_playback to
- </p><pre class="programlisting">ActionSequence_< mpl::vector<some_action, start_playback> ></pre><p>and
- now will execute some_action and start_playback every time the transition is
- taken. ActionSequence_ is a functor calling each action of the mpl::vector
- in sequence.</p><p>We also want to replace good_disk_format by a condition of the type:
- “good_disk_format && (some_condition || some_other_condition)”. We
- can achieve this using And_ and Or_ functors:
- </p><pre class="programlisting">And_<good_disk_format,Or_< some_condition , some_other_condition> ></pre><p>It
- even starts looking like functional programming. MSM ships with functors for
- operators, state machine usage, STL algorithms or container methods.</p></div><div class="sect2" title="Defining states with entry/exit actions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1281"></a>Defining states with entry/exit actions</h3></div></div></div><p>You probably noticed that we just showed a different transition table and
- that we even mixed rows from different front-ends. This means that you can
- do this and leave the definitions for states unchanged. Most examples are
- doing this as it is the simplest solution. You still enjoy the simplicity of
- the first front-end with the extended power of the new transition types.
- This <a class="link" href="examples/SimpleWithFunctors.cpp" target="_top">tutorial</a>,
- adapted from the earlier example does just this.</p><p>Of course, it is also possible to define states where entry and exit
- actions are also provided as functors as these are generated by eUML and
- both front-ends are equivalent. For example, we can define a state
- as:</p><pre class="programlisting">struct Empty_Entry
- {
- template <class Event,class Fsm,class State>
- void operator()(Event const&,Fsm&,State&)
- {
- ...
- }
- }; // same for Empty_Exit
- struct Empty_tag {};
- struct Empty : public msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit>{};</pre><p>This also means that you can, like in the transition table, write entry /
- exit actions made of more complicated action combinations. The previous
- example can therefore <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">be
- rewritten</a>.</p><p>Usually, however, one will probably use the standard state definition as
- it provides the same capabilities as this front-end state definition, unless
- one needs some of the shipped predefined functors or is a fan of functional
- programming.</p></div><div class="sect2" title="What do you actually do inside actions / guards (Part 2)?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1300"></a><span class="command"><strong><a name="functor-front-end-actions"></a></strong></span>What do you actually do inside actions / guards (Part 2)?</h3></div></div></div><p>Using the basic front-end, we saw how to pass data to actions through the
- event, that data common to all states could be stored in the state machine,
- state relevant data could be stored in the state and access as template
- parameter in the entry / exit actions. What was however missing was the
- capability to access relevant state data in the transition action. This is
- possible with this front-end. A transition's source and target state are
- also given as arguments. If the current calculation's state was to be found
- in the transition's source state (whatever it is), we could access
- it:</p><pre class="programlisting">struct send_rocket
- {
- template <class Fsm,class Evt,class SourceState,class TargetState>
- void operator()(Evt const&, Fsm& fsm, SourceState& src,TargetState& )
- {
- fire_rocket(evt.direction, src.current_calculation);
- }
- }; </pre><p>It was a little awkward to generate new events inside actions with the basic
- front-end. With the functor front-end it is much cleaner:</p><pre class="programlisting">struct send_rocket
- {
- template <class Fsm,class Evt,class SourceState,class TargetState>
- void operator()(Evt const& evt, Fsm& fsm, SourceState& src,TargetState&)
- {
- fire_rocket(evt.direction, src.current_calculation);
- fsm.process_event(rocket_launched());
- }
- }; </pre></div><div class="sect2" title="Defining a simple state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1312"></a>Defining a simple state machine</h3></div></div></div><p>Like states, state machines can be defined using the previous front-end,
- as the previous example showed, or with the functor front-end, which allows
- you to define a state machine entry and exit functions as functors, as in
- <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">this
- example</a>.</p></div><div class="sect2" title="Anonymous transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1320"></a>Anonymous transitions</h3></div></div></div><p>Anonymous (completion) transitions are transitions without a named event.
- We saw how this front-end uses <code class="code">none</code> when no action or guard is
- required. We can also use <code class="code">none</code> instead of an event to mark an
- anonymous transition. For example, the following transition makes an
- immediate transition from State1 to State2:</p><pre class="programlisting">Row < State1 , none , State2 ></pre><p>The following transition does the same but calling an action in the
- process:</p><pre class="programlisting">Row < State1 , none , State2 , State1ToState2, none ></pre><p>The following diagram shows an example and its <a class="link" href="examples/AnonymousTutorialWithFunctors.cpp" target="_top">implementation</a>:</p><p><span class="inlinemediaobject"><img src="../images/Anonymous.jpg" width="70%"></span></p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1346"></a><span class="command"><strong><a name="functor-internal-transitions"></a></strong></span>Internal
- transitions</h3></div></div></div><p>The <a class="link" href="examples/SimpleTutorialInternalFunctors.cpp" target="_top">following example</a> uses internal transitions with the functor
- front-end. As for the simple standard front-end, both methods of defining
- internal transitions are supported:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>providing a <code class="code">Row</code> in the state machine's transition
- table with <code class="code">none</code> as target state defines an internal
- transition.</p></li><li class="listitem"><p>providing an <code class="code">internal_transition_table</code> made of
- <code class="code">Internal</code> rows inside a state or submachine
- defines UML-conform internal transitions with higher
- priority.</p></li><li class="listitem"><p>transitions defined inside
- <code class="code">internal_transition_table</code> require no source or
- target state as the source state is known (<code class="code">Internal</code>
- really are <code class="code">Row</code> without a source or target state)
- .</p></li></ul></div><p>Like for the <span class="command"><strong><a class="command" href="ch03s02.html#internal-transitions-note">standard front-end internal transitions</a></strong></span>, internal transition
- tables are added into the main state machine's table, thus allowing you to
- distribute the transition table definition and reuse states.</p><p>There is an added bonus offered for submachines, which can have both the
- standard transition_table and an internal_transition_table (which has higher
- priority). This makes it easier if you decide to make a full submachine from
- a state later. It is also slightly faster than the standard alternative,
- adding orthogonal regions, because event dispatching will, if accepted by
- the internal table, not continue to the subregions. This gives you a O(1)
- dispatch instead of O(number of regions). While the example is with eUML,
- the same is also possible with this front-end.</p></div><div class="sect2" title="Kleene (any) event"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1392"></a><span class="command"><strong><a name="any-event"></a></strong></span>Kleene (any) event</h3></div></div></div><p>Normally, MSM requires an event to fire a transition. But there are cases,
- where any event, no matter which one would do:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>If you want to reduce the number of transitions: any event
- would do, possibly will guards decide what happens</p></li><li class="listitem"><p>Pseudo entry states do not necessarily want to know the event
- which caused their activation, or they might want to know only a
- property of it.</p></li></ul></div><p>MSM supports a boost::any as an acceptable event. This event will match
- any event, meaning that if a transition with boost::any as event originates
- from the current state, this transition would fire (provided no guards or
- transition with a higher priority fires first). This event is named Kleene,
- as reference top the Kleene star used in a regex.</p><p>For example, this transition on a state machine instance named fsm:</p><pre class="programlisting">Row < State1, boost::any, State2></pre><p>will fire if State1 is active and an event is processed:</p><pre class="programlisting">fsm.process_event(whatever_event());</pre><p>At this point, you can use this <span class="italic">any</span>
- event in transition actions to get back to the original event by calling for
- example<span class="italic"> boost::any::type()</span>.</p><p>It is also possible to support your own Kleene events by specializing
- boost::msm::is_kleene_event for a given event, for example:</p><pre class="programlisting">namespace boost { namespace msm{
- template<>
- struct is_kleene_event< my_event >
- {
- typedef boost::mpl::true_ type;
- };
- }}</pre><p>The only requirement is that this event must have a copy constructor from
- the event originally processed on the state machine.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Basic front-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> eUML</td></tr></table></div></body></html>
|