The c++ template metaprogramming( Chapter 11. A DSEL Design )

#include "stdafx.h"
#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/filter_view.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/static_assert.hpp>
#include <vector>
#include <ctime>
#include <cassert>


namespace mpl = boost::mpl;
using namespace mpl::placeholders;

//通过递归的“分派”
template<
	class Transition
		, class Next
>
struct event_dispatcher
{  //Finite State Machines
	typedef typename Transition::fsm_t fsm_t;
	typedef typename Transition::event event;

	static int dispatch(
		fsm_t& fsm, int state, event const& e)
	{
		if (state == Transition::current_state)
		{
			Transition::execute(fsm, e);
			return Transition::next_state;
		}
		else // move on to the next node in the chain.
		{
			return Next::dispatch(fsm, state, e);
		}
	}

};



template <class Derived> class state_machine;
//默认的转发,实际上是一个初始值。
struct default_event_dispatcher
{
	template<class FSM, class Event>
	static int dispatch(
		state_machine<FSM>& m, int state, Event const& e)
	{
		return m.call_no_transition(state, e);
	}
};


template<class Table, class Event>
struct generate_dispatcher;

template<class Derived>
class state_machine
{
	// ...
protected:
	template<
		int CurrentState
		, class Event
		, int NextState
		, void (*action)(Derived&, Event const&)
	>
	struct row
	{
		// for later use by our metaprogram
		enum { current_state = CurrentState };
		enum { next_state = NextState };
		typedef Event event;
		typedef Derived fsm_t;

		// do the transition action.
		static void execute(Derived& fsm, Event const& e)
		{
			(*action)(fsm, e);
		}
	};


	friend struct default_event_dispatcher;

	template <class Event>
	int call_no_transition(int state, Event const& e)
	{
		return static_cast<Derived*>(this)->no_transition(state, e);  // CRTP downcast
			
	}
	// 
public:
		template<class Event>
	int process_event(Event const& evt)
	{
		// generate the dispatcher type.
		typedef typename generate_dispatcher<
			/*typename*/ Derived::transition_table, Event
		>::type dispatcher;//相同的"Event"为一个row
      
		// dispatch the event.
		//这儿来递归的调用。对于相同的"Event",用state来区分。
		this->state = dispatcher::dispatch(
			*static_cast<Derived*>(this)        // CRTP downcast
			, this->state
			, evt
			);

		// return the new state
		return this->state;
	}

	// ...
protected:
	state_machine()
		: state(Derived::initial_state)
	{
	}

private:
	int state;
	// ...

	// ...
public:
	template <class Event>
	int no_transition(int state, Event const& e)
	{
	//	assert(false);
		return state;
	}
	// ...
	
};

//在元编程中的固定写法。用类封装。
template <class Event> 
struct is_same_event
{
	template <class Transition> struct apply
		: boost::is_same<Event,typename Transition::event>
	{//is_same比较两者类型是否相同,如果一者有const,另外一个没有const,这样算不同的类型。
	};
};
//is_same_event比较"event"是否相同
//filter_view,把相同的"event"存放在一起。
//fold对相同的这些"event"调用方法。
/*
template<typename Sequence
        ,typename State   
		,typename ForwardOp    
        >struct fold
{
	typedef unspecified type;
};
描述持续调用二元 ForwardOp,
以上一次调用 ForwardOp 所得结果(第一次调用时使用 State)和区间 
[begin<Sequence>::type, end<Sequence>::type) 的每个元素为参数,
返回最终的结果。
*/

template<class Table, class Event>
struct generate_dispatcher
	: mpl::fold<
	mpl::filter_view<   // select rows triggered by Event
	Table
	, is_same_event<Event>
	>
	, default_event_dispatcher
	, event_dispatcher<_2,_1> 
	>
{};
//全例子最难的就是这个算法调用。上面的调用经过扩展,当参数是
//open_close()的时候
//event_dispatcher<state_machine<player>::row<4,open_close,1,&player::stop_and_open>,
		//	event_dispatcher<state_machine<player>::row<3,open_close,1,&player::stop_and_open>,
		//  event_dispatcher<state_machine<player>::row<0,open_close,1,&player::open_drawer>,
		//  event_dispatcher<state_machine<player>::row<2,open_close,1,&player::open_drawer>,default_event_dispatcher>>>>
//可以利用新建对象的方法来跟踪其类型。这是一个诀窍。

struct play {};
struct open_close {};
struct cd_detected { 
	cd_detected(char const*, std::vector<clock_t> const&) {}
};
#ifdef __GNUC__ // in which pause seems to have a predefined meaning
# define pause pause_
#endif
struct pause {};
struct stop {};


// concrete FSM implementation 
class player : public state_machine<player>
{
public:
	// the list of FSM states
	enum states {
		Empty, Open, Stopped, Playing, Paused
		, initial_state = Empty
	};


#ifdef __MWERKS__
public: // Codewarrior bug workaround.  Tested at 0x3202
#endif

	static void start_playback(player&, play const&);
	static void open_drawer(player&, open_close const&);
	static void close_drawer(player&, open_close const&);
	static void store_cd_info(player&, cd_detected const&);
	static void stop_playback(player&, stop const&);
	static void pause_playback(player&, pause const&);
	static void resume_playback(player&, play const&);
	static void stop_and_open(player&, open_close const&);


#ifdef __MWERKS__
private:
#endif 
	friend class state_machine<player>;
	typedef player p; // makes transition table cleaner

	// transition table
	struct transition_table : mpl::vector<

		//    Start     Event         Next      Action
		//  +---------+-------------+---------+------------------+
		row < Stopped , play        , Playing , &start_playback  >,
		row < Stopped , open_close  , Open    , &open_drawer     >,
		//  +---------+-------------+---------+------------------+
		row < Open    , open_close  , Empty   , &close_drawer    >,
		//  +---------+-------------+---------+------------------+
		row < Empty   , open_close  , Open    , &open_drawer     >,
		row < Empty   , cd_detected , Stopped , &store_cd_info   >,
		//  +---------+-------------+---------+------------------+
		row < Playing , stop        , Stopped , &stop_playback   >,
		row < Playing , pause       , Paused  , &pause_playback  >,
		row < Playing , open_close  , Open    , &stop_and_open   >,
		//  +---------+-------------+---------+------------------+
		row < Paused  , play        , Playing , &resume_playback >,
		row < Paused  , stop        , Stopped , &stop_playback   >,
		row < Paused  , open_close  , Open    , &stop_and_open   >
		//  +---------+-------------+---------+------------------+

	> {};
	typedef

		event_dispatcher<
		row<Stopped, play const, Playing, &start_playback>
		, event_dispatcher<
		row<Paused, play const, Playing, &resume_playback>
		, default_event_dispatcher
		>
		>
		dummy;
};

void player::start_playback(player&, play const&)
{
	std::cout<<"start_playback "<< std::endl;
}

void player::open_drawer(player&, open_close const&)
{
	std::cout<<"open_drawer "<< std::endl;
}

void player::close_drawer(player&, open_close const&)
{
	std::cout<<"close_drawer "<< std::endl;
}
void player::store_cd_info(player&, cd_detected const&)
{
	std::cout<<"store_cd_info "<< std::endl;
}

void player::stop_playback(player&, stop const&)
{
	std::cout<<"stop_playback "<< std::endl;
}

void player::pause_playback(player&, pause const&)
{
	std::cout<<"pause_playback "<< std::endl;
}

void player::resume_playback(player&, play const&)
{
	std::cout<<"resume_playback "<< std::endl;
}

void player::stop_and_open(player&, open_close const&)
{
	std::cout<<"stop_and_open "<<std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{ 
	player p;                      // An instance of the FSM

	p.process_event(open_close()); // user opens CD player
	p.process_event(open_close()); // inserts CD and closes
	p.process_event(               // CD is detected
		cd_detected(
		"Louie, Louie"
		, std::vector<clock_t>( /* track lengths */ )
		)
		);
	p.process_event(play());       // etc.
	p.process_event(pause());
	p.process_event(play());
	p.process_event(stop());

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yshuise

权术横行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值