c++ 泛型 程式設計 之 Functor 設計模式

Sunday發表於2015-02-25

完整程式碼見: 

 http://download.csdn.net/detail/zhuyingqingfen/8457091


#ifndef FUNCTOR_H_
#define FUNCTOR_H_

#include "typelists.h"
#include "typetraits.h"

template<typename R,class TList>class FunctorImpl;
template<typename R>
class FunctorImpl<R,NullType>
{
public:
	virtual R operator()() = 0;
	//Clone 目的是為了產生FunctorImpl物件的一份多型(通過基類指標呼叫實際的物件的Clone方法)拷貝
	//這個也用到了“協變式返回型別"特性,即你可以在子類中改寫返回值型別,指向子類(pointer to derived class)
	virtual FunctorImpl * Clone()const = 0;
	virtual ~FunctorImpl(){}//虛建構函式的作用是當刪除FunctorImpl的指標時,能夠呼叫FunctorImpl的
	//派生類的指標。
};
template<typename R,typename P1>
class FunctorImpl<R,TYPELIST_1(P1)>
{
public:
	virtual R operator()(P1) = 0;
	virtual FunctorImpl * Clone()const = 0;
	virtual ~FunctorImpl(){}
};
template<typename R,typename P1,typename P2>
class FunctorImpl<R,TYPELIST_2(P1,P2)>
{
public:
	virtual R operator()(P1,P2) = 0;
	virtual FunctorImpl * Clone()const = 0;
	virtual ~FunctorImpl(){}
};

template<class ParentFunctor,typename Fun>
class FunctorHandler://普通函式實現
	public FunctorImpl<typename ParentFunctor::ResultType,typename ParentFunctor::ParmList>
{
public:
	typedef typename ParentFunctor::ResultType ResultType;

	FunctorHandler(const Fun & fun):_fun(fun){}
	FunctorHandler*Clone()const{return new FunctorHandler(*this);}
	ResultType operator()(){return _fun;}
	ResultType operator()(typename ParentFunctor::Parm1 p1){return _fun(p1);}
	ResultType operator()(typename ParentFunctor::Parm1 p1,typename ParentFunctor::Parm2 p2)
	{
		return _fun(p1,p2);
	}
private:
	Fun _fun;
};

template<class ParentFunctor,typename PointerToObj,typename PointerToMemFn>
class MemFunHandler : 
	public FunctorImpl<typename ParentFunctor::ResultType,typename ParentFunctor::ParmList>
{
public:
	typedef typename ParentFunctor::ResultType ResultType;

	MemFunHandler(const PointerToObj & pOjb,PointerToMemFn pMemFn)
		:_pObj(pOjb),_pMemFn(pMemFn){}
	MemFunHandler * Clone()const {return new MemFunHandler(*this);}
	ResultType operator()(){return ((*_pObj).*_pMemFn)();}
	ResultType operator()(typename ParentFunctor::Parm1 p1)
	{return ((*_pObj).*_pMemFn)(p1);}
	ResultType operator()(typename ParentFunctor::Parm1,typename ParentFunctor::Parm2)
	{return ((*_pObj).*_pMemFn)(p1,p2);}
	
private:
	PointerToObj _pObj;
	PointerToMemFn _pMemFn;
};
template<typename R,class TList>
class Functor
{
public:
	typedef R ResultType;
	typedef TList ParmList;
	typedef typename TypeAtNonStrict<TList,0,EmptyType>::Result Parm1;
	typedef typename TypeAtNonStrict<TList,1,EmptyType>::Result Parm2;

	//用來處理仿函式和普通函式
	template<typename Fun>
	explicit Functor(const Fun & fun)
		:spImpl(new FunctorHandler<Functor,Fun>(fun))
	{

	}
	//用來處理普通類成員函式
	template <class P, typename MF>
	explicit Functor(P const& pobj, MF memfun)
		:spImpl(new MemFunHandler<Functor,P,MF>(pobj,memfun))
	{
	}
	Functor():spImpl(0)
	{
	}
	Functor(const Functor & src)
	{
		spImpl = src.spImpl?src.spImpl->Clone():NULL;
	}
	Functor& operator = (const Functor &)
	{
		if (this != &src) {
			if (spImpl) delete spImpl;
			spImpl = src.spImpl? src.spImpl->Clone():NULL;
		}
		return *this;
	}
	R operator()(){return (*spImpl)();}
	R operator()(Parm1 p1){return (*spImpl)(p1);}
	R operator()(Parm1 p1,Parm2 p2){return (*spImpl)(p1,p2);}
private:
	typedef FunctorImpl<R,TList> Impl;
	std::auto_ptr<Impl>spImpl;
};
#endif

測試:

struct TestFunctor{
	void operator()(int i,double d)
	{
		std::cout<<"test functor:"<<i<<"  "<<d<<std::endl;
	}
};
void MysimpleFunction(int i,double d)
{
	std::cout<<"test functor:"<<i<<"  "<<d<<std::endl;
}
class MyClass
{
public:
	void test(int i){std::cout<<i<<std::endl;}
	void print(){std::cout<<"Myclass:print()"<<std::endl;}
}; 
void functor_test()
{
	std::cout<<"Functor Test:-----------"<<std::endl;
	TestFunctor f;
	Functor<void, TYPELIST_2(int,double)>cmd(f);

	typedef void (*PFun)(int,double);
	PFun pf  = MysimpleFunction; 

	/*(摘自網路)
	按照&運算子本來的意義,它要求其運算元是一個物件,但函式名不是物件(函式是一個物件),本來&test是非法的,但很久以前有些編譯器已經允許這樣做, 
	c/c++標準的制定者出於物件的概念已經有所發展的緣故,也承認了&test的合法性。 

	因此,對於test和&test你應該這樣理解,test是函式的首地址,它的型別是void (),&test表示一個指向函式test這個物件的地址, 
	它的型別是void (*)(),因此test和&test所代表的地址值是一樣的,但型別不一樣。test是一個函式,&test表示式的值是一個指標! 
	跟此問題類似的還有對一個陣列名取地址。 
	int a[100]; 
	printf("%p\n", a); 
	printf("%p\n", &a[0]); 

	列印值一樣。 
	但是陣列名a,指向的是具有100個int型別的組數; 
	&a[0]指向的是元素a[0]。 
	即他們的值相同,但指向的型別不同
	*/
 
	std::cout<<" 函式"<<MysimpleFunction<<" "<<&MysimpleFunction<<std::endl;
	Functor<void, TYPELIST_2(int,double)>cmd2(pf);
	//Functor<void, TYPELIST_2(int,double)>cmd2(&MysimpleFunction);
	Functor<void, TYPELIST_2(int,double)>cmd3(static_cast<PFun>(MysimpleFunction));
	cmd(2,3.4);
	cmd2(11,3.4455);
	cmd3(3,4.55);

	MyClass c;
	Functor<void,TYPELIST_0()> ff(&c,&MyClass::print);	
	ff();

	std::cout<<"End Functor Test.........."<<std::endl;
}


相關文章