The C ++ template metaprogramming (Chapter 11. A dsel design)

Source: Internet
Author: User

# 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/>}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.