|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r51233 - sandbox/msm/libs/msm/doc
From: christophe.j.henry_at_[hidden]
Date: 2009-02-12 17:26:12
Author: chenry
Date: 2009-02-12 17:26:11 EST (Thu, 12 Feb 2009)
New Revision: 51233
URL: http://svn.boost.org/trac/boost/changeset/51233
Log:
added user-defined base state documentation
Added:
sandbox/msm/libs/msm/doc/SM-0arg.cpp (contents, props changed)
sandbox/msm/libs/msm/doc/SM-1arg.cpp (contents, props changed)
sandbox/msm/libs/msm/doc/SM-3arg.cpp (contents, props changed)
Text files modified:
sandbox/msm/libs/msm/doc/index.html | 222 +++++++++++++++++++++++++++++++++++++++
1 files changed, 218 insertions(+), 4 deletions(-)
Added: sandbox/msm/libs/msm/doc/SM-0arg.cpp
==============================================================================
--- (empty file)
+++ sandbox/msm/libs/msm/doc/SM-0arg.cpp 2009-02-12 17:26:11 EST (Thu, 12 Feb 2009)
@@ -0,0 +1,478 @@
+#include <vector>
+#include <iostream>
+#include <string>
+#include <boost/mpl/vector/vector50.hpp>
+#include <boost/msm/state_machine.hpp>
+#include <boost/msm/tools.hpp>
+
+using namespace boost::msm;
+using namespace std;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct ThreeSec {};
+ struct TenSec {};
+ struct go_sleep {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ // forward
+ struct player;
+ struct cd_detected
+ {
+ cd_detected(std::string name, player& p)
+ : name(name)
+ , m_player(p)
+ {}
+
+ std::string name;
+ player& m_player;
+ };
+
+ // overwrite of the base state (not default)
+ struct my_visitable_state
+ {
+ // signature of the accept function
+ typedef args<void> accept_sig;
+
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept() const {}
+ };
+
+ // Concrete FSM implementation
+ struct player : public state_machine<player,NoHistory,my_visitable_state>
+ {
+ // The list of FSM states
+ struct Empty : public state<my_visitable_state>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Empty" << std::endl;}
+ void accept() const
+ {
+ std::cout << "visiting state:" << typeid(*this).name() << std::endl;
+ }
+ };
+ struct Open : public state<my_visitable_state>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Open" << std::endl;}
+ void accept() const
+ {
+ std::cout << "visiting state:" << typeid(*this).name() << std::endl;
+ }
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public state<my_visitable_state,SMPtr>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player* pl){m_player=pl;}
+ player* m_player;
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing : public state_machine<Playing,ShallowHistory<mpl::vector<end_pause> >,my_visitable_state >
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Playing" << std::endl;}
+ void accept()
+ {
+ std::cout << "visiting state:" << typeid(*this).name() << std::endl;
+ // visit substates
+ visit_current_states();
+ }
+ // The list of FSM states
+ // the Playing state machine contains a state which is himself a state machine
+ // so we have a SM containing a SM containing a SM
+ struct Song1 : public state_machine<Song1,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: First Song" << std::endl;}
+ void accept()
+ {
+ std::cout << "visiting state:" << typeid(*this).name() << std::endl;
+ }
+ struct LightOn : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOn" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOn" << std::endl;}
+ };
+ struct LightOff : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOff" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOff" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef LightOn initial_state;
+ // transition actions
+ void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Song1>;
+ typedef Song1 s; // makes transition table cleaner
+ // Transition table for Song1
+ struct transition_table : mpl::vector1<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+
+ };
+ struct Song2 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Playing>;
+ typedef Playing pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const&)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused : public state_machine<Paused,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Paused" << std::endl;}
+
+ // The list of FSM states
+ struct StartBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StartBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StartBlinking" << std::endl;}
+ };
+ struct StopBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StopBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StopBlinking" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef StartBlinking initial_state;
+ // transition actions
+ void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
+ void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Paused>;
+ typedef Paused pa; // makes transition table cleaner
+ // Transition table
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------+-------------+--------------+---------------------+----------------------+
+ a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
+ a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
+ // +---------------+-------------+---------------+--------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ struct SleepMode : public state<my_visitable_state> {}; // dumy state just to test the automatic id generation
+
+ struct AllOk : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public terminate_state<>
+ public interrupt_state<end_error,my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+ //typedef Empty initial_state; // this is to have only one active state
+
+#ifdef __MWERKS__
+ public: // Codewarrior bug workaround. Tested at 0x3202
+#endif
+ // transition actions
+ void start_playback(play const&) { std::cout << "player::start_playback\n"; }
+ void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
+ void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
+ void store_cd_info(cd_detected const&)
+ {
+ std::cout << "player::store_cd_info\n";
+ // generate another event to test the queue
+ //cd.m_player.process_event(play());
+ }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void start_sleep(go_sleep const&) { }
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+
+
+#ifdef __MWERKS__
+ private:
+#endif
+ // friend definition needed.
+ friend class state_machine<player>;
+ typedef player p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ // instead of the hard-coded array we can use fill_state_names:
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
+ typedef player::transition_table stt;
+ typedef generate_state_set<stt>::type all_states;
+ static char const* state_names[mpl::size<all_states>::value];
+ // fill the names of the states defined in the state machine
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(fill_state_names<stt>(state_names));
+
+ for (unsigned int i=0;i<p.current_state().size();++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+ void test()
+ {
+ player p;
+ // get a pointer to a state
+ // just to show how to do it as Stopped gets a pointer to player anyway
+ player::Stopped* tempstate = p.get_state<player::Stopped*>();
+ tempstate->m_player = &p;
+ // get a reference to a state
+ player::Stopped& tempstate2 = p.get_state<player::Stopped&>();
+ tempstate2.m_player = &p;
+ // make a copy of a state
+ player::Stopped tempstate3 = p.get_state<player::Stopped&>();
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ // visiting Paused and AllOk, but only Paused cares
+ p.visit_current_states();
+ p.process_event(open_close()); pstate(p);
+ // visiting Empty and AllOk, but only Empty cares
+ p.visit_current_states();
+
+
+ p.process_event(cd_detected("louie, louie",p));
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+ // at this point, Play is active, along FirstSong and LightOn
+ pstate(p);
+ // visiting Playing+Song1 and AllOk, but only Playing+Song1 care
+ p.visit_current_states();
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
+ // and of course on_entry on Paused and StartBlinking
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // forward events to Paused
+ p.process_event(TenSec());
+ p.process_event(TenSec());
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(ThreeSec()); pstate(p);
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ // visiting Playing+Song2 and AllOk, but only Playing cares
+ p.visit_current_states();
+
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
+ p.process_event(stop()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+ std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Simulate error. Event play is not valid" << std::endl;
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: sandbox/msm/libs/msm/doc/SM-1arg.cpp
==============================================================================
--- (empty file)
+++ sandbox/msm/libs/msm/doc/SM-1arg.cpp 2009-02-12 17:26:11 EST (Thu, 12 Feb 2009)
@@ -0,0 +1,488 @@
+#include <vector>
+#include <iostream>
+#include <string>
+#include <boost/mpl/vector/vector50.hpp>
+#include <boost/msm/state_machine.hpp>
+#include <boost/msm/tools.hpp>
+
+using namespace boost::msm;
+using namespace std;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct ThreeSec {};
+ struct TenSec {};
+ struct go_sleep {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ // forward
+ struct player;
+ struct cd_detected
+ {
+ cd_detected(std::string name, player& p)
+ : name(name)
+ , m_player(p)
+ {}
+
+ std::string name;
+ player& m_player;
+ };
+
+ // an easy visitor
+ struct SomeVisitor
+ {
+ template <class T>
+ void visit_state(T* astate)
+ {
+ std::cout << "visiting state:" << typeid(*astate).name() << std::endl;
+ }
+ };
+ // overwrite of the base state (not default)
+ struct my_visitable_state
+ {
+ // signature of the accept function
+ typedef args<void,SomeVisitor&> accept_sig;
+
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&) const {}
+ };
+
+ // Concrete FSM implementation
+ struct player : public state_machine<player,NoHistory,my_visitable_state>
+ {
+ // The list of FSM states
+ struct Empty : public state<my_visitable_state>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Empty" << std::endl;}
+ void accept(SomeVisitor& vis) const
+ {
+ vis.visit_state(this);
+ }
+ };
+ struct Open : public state<my_visitable_state>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Open" << std::endl;}
+ void accept(SomeVisitor& vis) const
+ {
+ vis.visit_state(this);
+ }
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public state<my_visitable_state,SMPtr>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player* pl){m_player=pl;}
+ player* m_player;
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing : public state_machine<Playing,ShallowHistory<mpl::vector<end_pause> >,my_visitable_state >
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Playing" << std::endl;}
+ void accept(SomeVisitor& vis)
+ {
+ vis.visit_state(this);
+ // visit substates
+ visit_current_states(vis);
+ }
+ // The list of FSM states
+ // the Playing state machine contains a state which is himself a state machine
+ // so we have a SM containing a SM containing a SM
+ struct Song1 : public state_machine<Song1,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: First Song" << std::endl;}
+ void accept(SomeVisitor& vis)
+ {
+ vis.visit_state(this);
+ }
+ struct LightOn : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOn" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOn" << std::endl;}
+ };
+ struct LightOff : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOff" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOff" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef LightOn initial_state;
+ // transition actions
+ void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Song1>;
+ typedef Song1 s; // makes transition table cleaner
+ // Transition table for Song1
+ struct transition_table : mpl::vector1<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+
+ };
+ struct Song2 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Playing>;
+ typedef Playing pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const&)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused : public state_machine<Paused,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Paused" << std::endl;}
+
+ // The list of FSM states
+ struct StartBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StartBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StartBlinking" << std::endl;}
+ };
+ struct StopBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StopBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StopBlinking" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef StartBlinking initial_state;
+ // transition actions
+ void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
+ void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Paused>;
+ typedef Paused pa; // makes transition table cleaner
+ // Transition table
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------+-------------+--------------+---------------------+----------------------+
+ a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
+ a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
+ // +---------------+-------------+---------------+--------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ struct SleepMode : public state<my_visitable_state> {}; // dumy state just to test the automatic id generation
+
+ struct AllOk : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public terminate_state<>
+ public interrupt_state<end_error,my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+ //typedef Empty initial_state; // this is to have only one active state
+
+#ifdef __MWERKS__
+ public: // Codewarrior bug workaround. Tested at 0x3202
+#endif
+ // transition actions
+ void start_playback(play const&) { std::cout << "player::start_playback\n"; }
+ void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
+ void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
+ void store_cd_info(cd_detected const&)
+ {
+ std::cout << "player::store_cd_info\n";
+ // generate another event to test the queue
+ //cd.m_player.process_event(play());
+ }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void start_sleep(go_sleep const&) { }
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+
+
+#ifdef __MWERKS__
+ private:
+#endif
+ // friend definition needed.
+ friend class state_machine<player>;
+ typedef player p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ // instead of the hard-coded array we can use fill_state_names:
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
+ typedef player::transition_table stt;
+ typedef generate_state_set<stt>::type all_states;
+ static char const* state_names[mpl::size<all_states>::value];
+ // fill the names of the states defined in the state machine
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(fill_state_names<stt>(state_names));
+
+ for (unsigned int i=0;i<p.current_state().size();++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+ void test()
+ {
+ player p;
+ // get a pointer to a state
+ // just to show how to do it as Stopped gets a pointer to player anyway
+ player::Stopped* tempstate = p.get_state<player::Stopped*>();
+ tempstate->m_player = &p;
+ // get a reference to a state
+ player::Stopped& tempstate2 = p.get_state<player::Stopped&>();
+ tempstate2.m_player = &p;
+ // make a copy of a state
+ player::Stopped tempstate3 = p.get_state<player::Stopped&>();
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ // visiting Paused and AllOk, but only Paused cares
+ SomeVisitor vis;
+ p.visit_current_states(boost::ref(vis));
+ p.process_event(open_close()); pstate(p);
+ // visiting Empty and AllOk, but only Empty cares
+ p.visit_current_states(boost::ref(vis));
+
+
+ p.process_event(cd_detected("louie, louie",p));
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+ // at this point, Play is active, along FirstSong and LightOn
+ pstate(p);
+ // visiting Playing+Song1 and AllOk, but only Playing+Song1 care
+ p.visit_current_states(boost::ref(vis));
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
+ // and of course on_entry on Paused and StartBlinking
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // forward events to Paused
+ p.process_event(TenSec());
+ p.process_event(TenSec());
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(ThreeSec()); pstate(p);
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ // visiting Playing+Song2 and AllOk, but only Playing cares
+ p.visit_current_states(vis);
+
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
+ p.process_event(stop()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+ std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Simulate error. Event play is not valid" << std::endl;
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: sandbox/msm/libs/msm/doc/SM-3arg.cpp
==============================================================================
--- (empty file)
+++ sandbox/msm/libs/msm/doc/SM-3arg.cpp 2009-02-12 17:26:11 EST (Thu, 12 Feb 2009)
@@ -0,0 +1,492 @@
+#include <vector>
+#include <iostream>
+#include <string>
+// to increase the number of arguments of the accept method
+#define BOOST_MSM_VISITOR_ARG_SIZE 3
+#include <boost/mpl/vector/vector50.hpp>
+#include <boost/msm/state_machine.hpp>
+#include <boost/msm/tools.hpp>
+
+using namespace boost::msm;
+using namespace std;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct ThreeSec {};
+ struct TenSec {};
+ struct go_sleep {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ // forward
+ struct player;
+ struct cd_detected
+ {
+ cd_detected(std::string name, player& p)
+ : name(name)
+ , m_player(p)
+ {}
+
+ std::string name;
+ player& m_player;
+ };
+
+ // an easy visitor
+ struct SomeVisitor
+ {
+ template <class T>
+ void visit_state(T* astate,int i,const char* s)
+ {
+ std::cout << "visiting state:" << typeid(*astate).name()
+ << " with data:" << i << " and:" << s << std::endl;
+ }
+ };
+ // overwrite of the base state (not default)
+ struct my_visitable_state
+ {
+ // signature of the accept function
+ typedef args<void,SomeVisitor&,int,const char*> accept_sig;
+
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&,int,const char*) const {}
+ };
+
+ // Concrete FSM implementation
+ struct player : public state_machine<player,NoHistory,my_visitable_state>
+ {
+ // The list of FSM states
+ struct Empty : public state<my_visitable_state>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Empty" << std::endl;}
+ void accept(SomeVisitor& vis,int i,const char* s) const
+ {
+ vis.visit_state(this,i,s);
+ }
+ };
+ struct Open : public state<my_visitable_state>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Open" << std::endl;}
+ void accept(SomeVisitor& vis,int i,const char* s) const
+ {
+ vis.visit_state(this,i,s);
+ }
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public state<my_visitable_state,SMPtr>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player* pl){m_player=pl;}
+ player* m_player;
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing : public state_machine<Playing,ShallowHistory<mpl::vector<end_pause> >,my_visitable_state >
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Playing" << std::endl;}
+ void accept(SomeVisitor& vis,int i,const char* s)
+ {
+ vis.visit_state(this,i,s);
+ // visit substates
+ visit_current_states(vis,i,s);
+ }
+ // The list of FSM states
+ // the Playing state machine contains a state which is himself a state machine
+ // so we have a SM containing a SM containing a SM
+ struct Song1 : public state_machine<Song1,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: First Song" << std::endl;}
+ void accept(SomeVisitor& vis,int i,const char* s)
+ {
+ vis.visit_state(this,i,s);
+ }
+ struct LightOn : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOn" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOn" << std::endl;}
+ };
+ struct LightOff : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: LightOff" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: LightOff" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef LightOn initial_state;
+ // transition actions
+ void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Song1>;
+ typedef Song1 s; // makes transition table cleaner
+ // Transition table for Song1
+ struct transition_table : mpl::vector1<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+
+ };
+ struct Song2 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Playing>;
+ typedef Playing pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const&)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused : public state_machine<Paused,NoHistory,my_visitable_state>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "leaving: Paused" << std::endl;}
+
+ // The list of FSM states
+ struct StartBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StartBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StartBlinking" << std::endl;}
+ };
+ struct StopBlinking : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: StopBlinking" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: StopBlinking" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef StartBlinking initial_state;
+ // transition actions
+ void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
+ void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
+ // guard conditions
+
+ // friend definition needed.
+ friend class state_machine<Paused>;
+ typedef Paused pa; // makes transition table cleaner
+ // Transition table
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------+-------------+--------------+---------------------+----------------------+
+ a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
+ a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
+ // +---------------+-------------+---------------+--------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+ struct SleepMode : public state<my_visitable_state> {}; // dumy state just to test the automatic id generation
+
+ struct AllOk : public state<my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public terminate_state<>
+ public interrupt_state<end_error,my_visitable_state>
+ {
+ template <class Event>
+ void on_entry(Event const& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event>
+ void on_exit(Event const& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+ //typedef Empty initial_state; // this is to have only one active state
+
+#ifdef __MWERKS__
+ public: // Codewarrior bug workaround. Tested at 0x3202
+#endif
+ // transition actions
+ void start_playback(play const&) { std::cout << "player::start_playback\n"; }
+ void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
+ void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
+ void store_cd_info(cd_detected const&)
+ {
+ std::cout << "player::store_cd_info\n";
+ // generate another event to test the queue
+ //cd.m_player.process_event(play());
+ }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void start_sleep(go_sleep const&) { }
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+
+
+#ifdef __MWERKS__
+ private:
+#endif
+ // friend definition needed.
+ friend class state_machine<player>;
+ typedef player p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class Event>
+ int no_transition(int state, Event const& )
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(Event).name() << std::endl;
+ return state;
+ }
+ };
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ // instead of the hard-coded array we can use fill_state_names:
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
+ typedef player::transition_table stt;
+ typedef generate_state_set<stt>::type all_states;
+ static char const* state_names[mpl::size<all_states>::value];
+ // fill the names of the states defined in the state machine
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(fill_state_names<stt>(state_names));
+
+ for (unsigned int i=0;i<p.current_state().size();++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+ void test()
+ {
+ player p;
+ // get a pointer to a state
+ // just to show how to do it as Stopped gets a pointer to player anyway
+ player::Stopped* tempstate = p.get_state<player::Stopped*>();
+ tempstate->m_player = &p;
+ // get a reference to a state
+ player::Stopped& tempstate2 = p.get_state<player::Stopped&>();
+ tempstate2.m_player = &p;
+ // make a copy of a state
+ player::Stopped tempstate3 = p.get_state<player::Stopped&>();
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ // visiting Paused and AllOk, but only Paused cares
+ SomeVisitor vis;
+ p.visit_current_states(boost::ref(vis),1,"first");
+ p.process_event(open_close()); pstate(p);
+ // visiting Empty and AllOk, but only Empty cares
+ p.visit_current_states(boost::ref(vis),2,"second");
+
+
+ p.process_event(cd_detected("louie, louie",p));
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+ // at this point, Play is active, along FirstSong and LightOn
+ pstate(p);
+ // visiting Playing+Song1 and AllOk, but only Playing+Song1 care
+ p.visit_current_states(boost::ref(vis),3,"third");
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
+ // and of course on_entry on Paused and StartBlinking
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // forward events to Paused
+ p.process_event(TenSec());
+ p.process_event(TenSec());
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(ThreeSec()); pstate(p);
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ // visiting Playing+Song2 and AllOk, but only Playing cares
+ p.visit_current_states(vis,4,"fourth");
+
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
+ p.process_event(stop()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+ std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Simulate error. Event play is not valid" << std::endl;
+ p.process_event(play()); pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Modified: sandbox/msm/libs/msm/doc/index.html
==============================================================================
--- sandbox/msm/libs/msm/doc/index.html (original)
+++ sandbox/msm/libs/msm/doc/index.html 2009-02-12 17:26:11 EST (Thu, 12 Feb 2009)
@@ -6,12 +6,13 @@
<META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)">
<META NAME="CREATED" CONTENT="20080922;21044300">
<META NAME="CHANGEDBY" CONTENT="Christophe Henry">
- <META NAME="CHANGED" CONTENT="20090130;5200">
+ <META NAME="CHANGED" CONTENT="20090212;23243800">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
<META NAME="Info 4" CONTENT="">
<META NAME="CHANGEDBY" CONTENT="Christophe Henry">
+ <META NAME="CHANGEDBY" CONTENT="Christophe Henry">
<META NAME="CHANGEDBY" CONTENT="xtoff">
<META NAME="CHANGEDBY" CONTENT="xtoff">
<META NAME="CHANGEDBY" CONTENT="xtoff">
@@ -74,6 +75,14 @@
pointer to a state</A></P>
<LI><P>Copying</P>
<LI><P>Exceptions</P>
+ <LI><P>Helpers methods</P>
+</UL>
+<P>Customizing states</P>
+<UL>
+ <LI><P><A HREF="#User-defined base state / Polymorphic states|outline">User-defined
+ base state / Polymorphic states</A></P>
+ <LI><P><A HREF="#Visiting active states|outline">Visiting active
+ states</A></P>
</UL>
<P>Performance</P>
<P>Compilers</P>
@@ -117,6 +126,7 @@
an alternative to Boost.Statechart state_downcast</P>
<LI><P>Interrupted Pseudo-State. A kind of Terminate pseudo-state
which can still be left.</P>
+ <LI><P>Visitors, polymorphic states when needed.</P>
</UL>
<P><BR><BR>
</P>
@@ -1898,6 +1908,208 @@
(std::exception& e)</FONT></FONT></FONT></CODE></P>
<P><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>Thus
giving you a chance to handle the exception.</FONT></FONT></FONT></CODE></P>
+<P><BR><BR>
+</P>
+<H2 CLASS="western"><A NAME="Helpers methods|outline"></A><CODE><FONT COLOR="#000000"><FONT FACE="Albany, sans-serif"><FONT SIZE=4>Helpers
+methods</FONT></FONT></FONT></CODE></H2>
+<P><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>msm::state_machine
+also provides a few helper methods which you might need but will
+probably not:</FONT></FONT></FONT></CODE></P>
+<UL>
+ <LI><P><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">const</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">std</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">::</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">vector</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG=""><</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">int</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">>&
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">current_state</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">()
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">const</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>:
+ the ids of currently active states</FONT></FONT></FONT></CODE></P>
+ <LI><P><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">const</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">BaseState</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">*
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">get_state_by_id</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">(</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">int</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">id</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">)
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">const</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>:
+ returns the state with the given id as a pointer to a (user- or
+ default-) base state.</FONT></FONT></FONT></CODE></P>
+ <LI><P><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">bool</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">is_contained</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">()
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">const</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>:
+ returns true if the state machine is used as a composite in another
+ state machine, false otherwise.</FONT></FONT></FONT></CODE></P>
+</UL>
+<P><BR><BR>
+</P>
+<H1 CLASS="western"><A NAME="8.Customizing states|outline"></A><CODE><FONT COLOR="#000000"><FONT FACE="Arial, sans-serif"><FONT SIZE=4 STYLE="font-size: 16pt"><SPAN STYLE="font-style: normal">Customizing
+states</SPAN></FONT></FONT></FONT></CODE></H1>
+<P>By default, all states derive from msm::default_base_state, which
+is neither polymorphic nor has other useful purpose than to define a
+base for all states. The following part will describe the
+customization possibilities offered by Msm.</P>
+<H2 CLASS="western"><A NAME="User-defined base state / Polymorphic states|outline"></A>
+<CODE><FONT COLOR="#000000"><FONT FACE="Albany, sans-serif"><FONT SIZE=3>User-defined
+base state / Polymorphic states</FONT></FONT></FONT></CODE></H2>
+<P>Sometimes you will need states to be polymorphic. You might want
+to use <FONT FACE="Times New Roman, serif">typeid</FONT> on them,
+like the tutorials do for logging.</P>
+<P>You might also need some added functionality in form of a virtual
+function.</P>
+<P>Msm offers these possibilities by allowing the base state to be
+user-defined. To do this, you need two simple changes:</P>
+<UL>
+ <LI><P>add the non-default base state in your <FONT FACE="Courier New, monospace">msm::state<>
+ </FONT>definition, as first template argument (except for
+ <FONT FACE="Courier New, monospace">interrupt_states</FONT> for
+ which it is the second argument, the first one being the event
+ ending the interrupt), for example, <FONT FACE="Courier New, monospace">my_base_state</FONT>
+ being your new base state for <U>all states</U> in a given state
+ machine: <BR><CODE><FONT COLOR="#0000ff"><FONT SIZE=3>struct</FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT SIZE=3>
+ </FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT SIZE=3>Empty</FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT SIZE=3>
+ : </FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT SIZE=3>public</FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT SIZE=3>
+ </FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT SIZE=3>state</FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT SIZE=3><my_base_state></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT SIZE=2><BR></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>Now,
+ </FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3>my_base_state</FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>
+ is your new base state. If it has a virtual function, your states
+ become polymorphic. Msm also provides a default polymorphic base
+ type for your convenience, </FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3>msm::polymorphic_</FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3>state</FONT></FONT></FONT></CODE></P>
+ <LI><P><CODE><FONT COLOR="#030003"><FONT FACE="Times New Roman, serif"><FONT SIZE=3>Add
+ the user-defined base state in the state machine definition, as a
+ third template argument (after History), for example:<BR></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">struct</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">player
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">:
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">public</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">
+ </SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">state_machine</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG=""><</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">player</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">,</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">NoHistory</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">,</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">my_base_state</SPAN></FONT></FONT></FONT></CODE><CODE><FONT COLOR="#000000"><FONT FACE="Courier New, mono
space"><FONT SIZE=3><SPAN LANG="">></SPAN></FONT></FONT></FONT></CODE></P>
+</UL>
+<P><BR><BR>
+</P>
+<P><CODE><FONT COLOR="#000000"><FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN LANG="">You
+now have polymorphic states. Please have a look at <A HREF="SM-0arg.cpp">an
+example using polymorphic states</A> and the concept presented in the
+next paragraph, visitors.</SPAN></FONT></FONT></FONT></CODE></P>
+<H2 CLASS="western"><A NAME="Visiting active states|outline"></A><FONT SIZE=3>Visiting
+active states</FONT></H2>
+<P><FONT SIZE=3>In some cases, having only the id or a
+pointer-to-base of the currently active states is not enough. You
+might want to call non-virtually a method of the currently active
+states. It will not be said that Msm forces the <FONT FACE="Courier New, monospace">virtual</FONT>
+keyword down your throat! </FONT>
+</P>
+<P><FONT SIZE=3>To achieve this goal, Msm provides its own variation
+of a visitor pattern using the previously described user-defined
+state technique. If you add to your user-defined base state an
+<FONT FACE="Courier New, monospace">accept_sig</FONT> typedef giving
+the return value (unused for the moment) and signature and provide an
+<FONT FACE="Courier New, monospace">accept</FONT> method with the
+same signature, calling <FONT FACE="Courier New, monospace">state_machine::visit_current_states</FONT>
+will cause <FONT FACE="Courier New, monospace">accept</FONT> to be
+called on the currently active states. Typically, you will also want
+to provide an empty default <FONT FACE="Courier New, monospace">accept</FONT>
+in your base state in order to not force all your states to implement
+<FONT FACE="Courier New, monospace">accept</FONT>. For example your
+base state could be:</FONT></P>
+<P STYLE="margin-bottom: 0cm"> <FONT SIZE=3><FONT COLOR="#0000ff"><FONT FACE="Courier New, monospace"><SPAN LANG="">struct</SPAN></FONT></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><SPAN LANG="">
+</SPAN></FONT></FONT><FONT COLOR="#030003"><FONT FACE="Courier New, monospace"><SPAN LANG="">my_visitable_state</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3>{</FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+signature of the accept function</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">typedef</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">args</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG=""><</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">>
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept_sig</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">;</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><BR>
+</P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+we also want polymorphic states</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">virtual</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+~</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">my_visitable_state</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">()
+{}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+default implementation for states who do not need to be visited</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">()
+</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">const</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+{}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">};</SPAN></FONT></FONT></FONT></P>
+<P><BR><BR>
+</P>
+<P><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">This makes your
+states polymorphic and visitable. In this case, </SPAN></FONT></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">accept</SPAN></FONT></FONT></FONT><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">
+is made const and takes no argument. It could also be:</SPAN></FONT></FONT></P>
+<P><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">struct</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">SomeVisitor</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+{…};</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">struct</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">my_visitable_state</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3>{</FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+signature of the accept function</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">typedef</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">args</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG=""><</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">,</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">SomeVisitor</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">&>
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept_sig</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">;</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><BR>
+</P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+we also want polymorphic states</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">virtual</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+~</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">my_visitable_state</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">()
+{}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+default implementation for states who do not need to be visited</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">(</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">SomeVisitor</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">&)
+</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">const</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+{}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">};</SPAN></FONT></FONT></FONT></P>
+<P><BR><BR>
+</P>
+<P><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">And now, </SPAN></FONT></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">accept</SPAN></FONT></FONT></FONT><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">
+will take one argument. It could also be non-const. </SPAN></FONT></FONT>
+</P>
+<P><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">By default,
+</SPAN></FONT></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">accept</SPAN></FONT></FONT></FONT><FONT COLOR="#000000"><FONT SIZE=3><SPAN LANG="">
+takes up to 2 arguments. To get more, simply #define
+</SPAN></FONT></FONT><FONT COLOR="#030003"><FONT SIZE=2><SPAN LANG="">BOOST_MSM_VISITOR_ARG_SIZE</SPAN></FONT></FONT><FONT COLOR="#030003"><FONT SIZE=3><SPAN LANG="">
+to another value before including state_machine.hpp. For example:</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">#define</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">BOOST_MSM_VISITOR_ARG_SIZE</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+3</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">#include</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#a31515"><SPAN LANG=""><boost/msm/state_machine.hpp></SPAN></FONT></FONT></FONT></P>
+<P><FONT COLOR="#030003"><FONT SIZE=3><SPAN LANG="">...</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">struct</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">my_visitable_state</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3>{</FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+signature of the accept function</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">typedef</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">args</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG=""><</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">,</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">SomeVisitor</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">&,</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">int</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">,</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">const</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">char</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">*>
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept_sig</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">;</SPAN></FONT></FONT></FONT></P>
+<P LANG="" STYLE="margin-bottom: 0cm"><BR>
+</P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+we also want polymorphic states</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">virtual</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+~</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">my_visitable_state</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">()
+{}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#008000"><SPAN LANG="">//
+default implementation for states who do not need to be visited. Not
+const</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> </FONT><FONT FACE="Courier New, monospace"><FONT SIZE=3><FONT COLOR="#0000ff"><SPAN LANG="">void</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">accept</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">(</SPAN></FONT><FONT COLOR="#030003"><SPAN LANG="">SomeVisitor</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">&,</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">int</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">,</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">const</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">
+</SPAN></FONT><FONT COLOR="#0000ff"><SPAN LANG="">char</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG="">*)
+</SPAN></FONT><FONT COLOR="#000000"><SPAN LANG=""> {}</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><FONT COLOR="#000000"> <FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN LANG="">};</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><BR>
+</P>
+<P STYLE="margin-bottom: 0cm"><FONT FACE="Times New Roman, serif"><FONT SIZE=3><FONT COLOR="#000000"><SPAN LANG="">You
+now only need implement </SPAN></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><SPAN LANG="">accept</SPAN></FONT></FONT><FONT COLOR="#000000"><SPAN LANG="">
+in states needing it. Note that </SPAN></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><SPAN LANG="">accept</SPAN></FONT></FONT><FONT COLOR="#000000"><SPAN LANG="">
+will be called on ALL active states but not automatically on
+substates of a composite. You can however choose to have it called by
+calling </SPAN></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><SPAN LANG="">visit_current_states</SPAN></FONT></FONT><FONT COLOR="#000000"><SPAN LANG="">
+in the </SPAN></FONT><FONT COLOR="#000000"><FONT FACE="Courier New, monospace"><SPAN LANG="">accept</SPAN></FONT></FONT><FONT COLOR="#000000"><SPAN LANG="">
+of the composite.</SPAN></FONT></FONT></FONT></P>
+<P STYLE="margin-bottom: 0cm"><BR>
+</P>
+<P STYLE="margin-bottom: 0cm"><FONT FACE="Times New Roman, serif"><FONT SIZE=3><FONT COLOR="#000000"><SPAN LANG="">Please
+have a look at the example using accept <A HREF="SM-0arg.cpp">with 0
+argument</A>, with 1, and <A HREF="SM-3arg.cpp">with
+3</A>.</SPAN></FONT></FONT></FONT></P>
<H1 CLASS="western"><A NAME="8.Performance|outline"></A>Performance</H1>
<P>Tests were made on different PCs running either Windows XP and
Vista and compiled with VC9 SP1 or Ubuntu and compiled with g++
@@ -1930,8 +2142,9 @@
<UL>
<LI><P>VC8,VC9, VC9SP1</P>
<LI><P>g++ 4.1 and g++ 4.2.3</P>
- <LI><P>partially g++ 3.3 (only <A HREF="SC%20Simple.cpp">simple
- state machines</A>)</P>
+ <LI><P>partially g++ 3.3-3.4 (only <A HREF="SC%20Simple.cpp">simple
+ state machines</A>). Composite state machines will compile but not
+ work properly.</P>
</UL>
<H1 CLASS="western" STYLE="margin-left: 0.68cm; text-indent: -0.76cm"><A NAME="8.Limitations|outline"></A>
Limitations</H1>
@@ -1959,7 +2172,8 @@
Alt</A> for using the framework with little documentation and to my
private reviewer, <A HREF="mailto:%20edouard%20DOT%20alligand%20AT%20bureau14%20DOT%20fr">Edouard
Alligand</A>.</P>
- <LI><P>Thanks to Jeff Flinn for his comments.</P>
+ <LI><P>Thanks to Jeff Flinn for his idea of the user-defined base
+ state.</P>
</UL>
<P><BR><BR>
</P>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk