# Include "stdafx. H "<br/> # include <iostream> <br/> # include <boost/MPL/fold. HPP> <br/> # include <boost/MPL/filter_view.hpp> <br/> # include <boost/type_traits/is_same.hpp> <br/> # include <boost/MPL/vector. HPP> <br/> # include <boost/MPL/placeholders. HPP> <br/> # include <boost/MPL/assert. HPP> <br/> # include <boost/static_assert.hpp> <br/> # include <vector> <br/> # include <ctime> <br/> # include <cassert> </P> <p> N Amespace MPL = boost: MPL; <br/> using namespace MPL: placeholders; </P> <p> // use recursive "dispatch" <br/> template <br/> class transition <br/>, class next <br/> struct event_dispatcher <br/> {// finite state machines <br/> typedef typename transition: fsm_t; <br/> typedef typename transition: Event event; </P> <p> static int dispatch (<br/> fsm_t & FSM, int state, event const & E) <br/>{< br/> If (State = tra Nsition: current_state) <br/>{< br/> transition: Execute (FSM, e); <br/> return transition: next_state; <br/>}< br/> else // move on to the next node in the chain. <br/>{< br/> return next: Dispatch (FSM, state, e ); <br/>}</P> <p >}; </P> <p> template <class derived> class state_machine; <br/> // The default Forwarding is actually an initial value. <Br/> struct default_event_dispatcher <br/>{< br/> template <class FSM, class event> <br/> static int dispatch (<br/> state_machine <FSM> & M, int state, event const & E) <br/> {<br/> return M. call_no_transition (State, e); <br/>}< br/>}; </P> <p> template <class table, class event> <br/> struct generate_dispatcher; </P> <p> template <class derived> <br/> class state_machine <br/> {<br/> //... <br/> protected: <br/> Te Mplate <br/> int currentstate <br/>, class event <br/>, int nextstate <br/>, void (* Action) (derived &, event const &) <br/> struct row <br/> {<br/> // for later use by our metaprogram <br/> Enum {current_state = currentstate }; <br/> Enum {next_state = nextstate}; <br/> typedef event; <br/> typedef derived fsm_t; </P> <p> // do the transition action. <br/> static void execute (derived & FSM, Eve NT const & E) <br/>{< br/> (* Action) (FSM, e); <br/>}< br/> }; </P> <p> friend struct default_event_dispatcher; </P> <p> template <class event> <br/> int call_no_transition (INT state, event const & E) <br/>{< br/> return static_cast <derived *> (this)-> no_transition (State, e ); // crtp downcast </P> <p >}< br/> // <br/> public: <br/> template <class event> <br/> int process_event (event const & EVT) <br/>{< br/> // generate The dispatcher type. <br/> typedef typename generate_dispatcher <br/>/* typename */derived: transition_table, event <br/>: Type dispatcher; // The same "Event" is a row </P> <p> // dispatch the event. <br/> // recursive call here. For the same "Event", use state to differentiate. <Br/> This-> state = DISPATCHER: Dispatch (<br/> * static_cast <derived *> (this) // crtp downcast <br/>, this-> state <br/>, EVT <br/>); </P> <p> // return the new State <br/> return this-> state; <br/>}</P> <p> //... <br/> protected: <br/> state_machine () <br/>: State (derived: initial_state) <br/>{< br/>}</P> <p> PRIVATE: <br/> int state; <br/> //... </P> <p> //... <br/> Public: <br/> template <class event> <br/> int n O_transition (INT state, event const & E) <br/>{< br/> // assert (false); <br/> return state; <br/>}< br/> //... <br/> /// <br/>}; </P> <p> // fixed syntax in metaprogramming. Class encapsulation. <Br/> template <class event> <br/> struct is_same_event <br/>{< br/> template <class transition> struct apply <br/>: boost :: is_same <event, typename transition: Event> <br/> {// is_same checks whether the two types are the same. If one has a const and the other has no const, different types are considered. <Br/>}; <br/> // comparison between is_same_event and "Event" <br/> // filter_view, store the same "Event" together. <Br/> // fold the same "Event" Call method. <Br/>/* <br/> template <typename sequence <br/>, typename state <br/>, typename forwardop <br/> struct fold <br/>{< br/> typedef unspecified type; <br/>}; <br/> Description: The binary forwardop is continuously called, <br/> the preceding forwardop call result (State used for the first call) and interval <br/> [begin <sequence >:: type, end <sequence >:: type) <br/> returns the final result. <Br/> */</P> <p> template <class table, class event> <br/> struct generate_dispatcher <br/>: MPL :: fold <br/> MPL: filter_view <// select rows triggered by event <br/> table <br/>, is_same_event <event> <br/>, default_event_dispatcher <br/>, event_dispatcher <_ 2, _ 1> <br/>>< br/> {}; <br/> // The most difficult example is to call this algorithm. The above call is extended. When the parameter is <br/> // open_close () <br/> // event_dispatcher <state_machine <player >:row <4, open_close, 1, & PLAYER: stop_and_open>, <br/> // event_dispatcher <state_machine <player>: Row <3, open_close, 1, & PLAYER: stop_and_open>, <br/> // event_dispatcher <state_machine <player>: Row <0, open_close, 1, & PLAYER: open_drawer>, <br/> // event_dispatcher <state_machine <player>: Row <2, open_close, 1, & PLAYER: open_drawer>, de Fault_event_dispatcher >>>< br/> // you can use the method of creating an object to track its type. This is a trick. </P> <p> struct play {}; <br/> struct open_close {}; <br/> struct cd_detected {<br/> cd_detected (char const *, STD:: vector <clock_t> const &) {}< br/> }; <br/> # ifdef _ gnuc _ // in which pause seems to have a predefined meaning <br/> # define pause _ <br/> # endif <br/> struct pause {}; <br/> struct stop {}; </P> <p> // concrete FSM implementation <br/> class player: public state_machine <player> <br/> {<br/> Public: <br/> // The list of FSM States <br/> Enum States {<br/> empty, open, stopped, playing, paused <br/>, initial_state = empty <br/>}; </P> <p> # ifdef _ mwerks __< BR/> public: // codewarrior bug workaround. tested at 0x3202 <br/> # endif </P> <p> static void start_playback (player &, play const &); <br/> static void open_drawer (player &, open_close const &); <br/> static void close_drawer (player &, open_close const &); <br/> static void store_cd_info (player &, cd_detected const &); <br/> static void stop_playback (player &, stop const &); <br/> static void pause_playback (player &, pause const &); <br/> static void resume_playback (player &, play const &); <br/> static void stop_and_open (player &, open_close const &); </P> <p> # ifdef _ mwerks __< BR/> PRIVATE: <br/> # endif <br/> friend class state_machine <player>; <br/> typedef player P; // makes transition table cleaner </P> <p> // transition table <br/> struct transition_table: MPL :: vector </P> <p> // start event next action <br/> // + --------- + ------------- + --------- + -------------------- + <br/> row <stopped, play, playing, & start_playback>, <br/> row <stopped, open_close, open, & open_drawer>, <br/> // + --------- + ------------- + --------- + ------------------ + <br/> row <open, open_close, empty, & close_drawer>, <br/> // + --------- + ------------- + --------- + ------------------ + <br/> row <empty, open_close, open, & open_drawer>, <br/> row <empty, cd_detected, stopped, & store_cd_info>, <br/> // + --------- + ------------- + --------- + ------------------ + <br/> row <playing, stop, stopped, & stop_playback>, <br/> row <playing, pause, paused, & pause_playback>, <br/> row <playing, open_close, open, & stop_and_open>, <br/> // + --------- + ------------- + --------- + ------------------ + <br/> row <paused, play, playing, & resume_playback>, <br/> row <paused, stop, stopped, & stop_playback>, <br/> row <paused, open_close, open, & stop_and_open> <br/> // + --------- + ------------- + --------- + ------------------ + </P> <p >> {}; <br/> typedef </P> <p> event_dispatcher <br/> row <stopped, play const, playing, & start_playback> <br/>, event_dispatcher <br/> row <paused, play const, playing, & resume_playback> <br/>, default_event_dispatcher <br/> dummy; <br/>}; </P> <p> void PLAYER: start_playback (player &, play const &) <br/>{< br/> STD :: cout <"start_playback" <STD: Endl; <br/>}</P> <p> void PLAYER: open_drawer (player &, open_close const &) <br/>{< br/> STD: cout <"open_drawer" <STD: Endl; <br/>}</P> <p> void PLAYER:: close_drawer (player &, open_close const &) <br/>{< br/> STD: cout <"close_drawer" <STD: Endl; <br/>}< br/> void PLAYER: store_cd_info (player &, cd_detected const &) <br/>{< br/> STD :: cout <"store_cd_info" <STD: Endl; <br/>}</P> <p> void PLAYER: stop_playback (player &, stop const &) <br/>{< br/> STD: cout <"stop_playback" <STD: Endl; <br/>}</P> <p> void PLAYER:: pause_playback (player &, pause const &) <br/>{< br/> STD: cout <"pause_playback" <STD: Endl; <br/>}</P> <p> void PLAYER: resume_playback (player &, play const &) <br/>{< br/> STD :: cout <"resume_playback" <STD: Endl; <br/>}</P> <p> void PLAYER: stop_and_open (player &, open_close const &) <br/>{< br/> STD: cout <"stop_and_open" <STD: Endl; <br/>}</P> <p> int _ tmain (INT argc, _ tchar * argv []) <br/>{< br/> player P; // an instance of the FSM </P> <p> P. process_event (open_close (); // user opens CD player <br/> P. process_event (open_close (); // inserts CD and closes <br/> P. process_event (// CD is detected <br/> cd_detected (<br/> "Louie, Louie" <br/>, STD :: vector <clock_t> (/* track lengths */) <br/>); <br/> P. process_event (play (); // etc. <br/> P. process_event (pause (); <br/> P. process_event (play (); <br/> P. process_event (stop (); </P> <p> return 0; <br/>}