在C++标准中,所有关于函数模板的API均在头文件funcitonal中,如mem_fun,函数模板主要的好处是将类的执行与具体类的实现分离开,这也是command设计模式中的一个关键特征.
在实现函数模式时,主要就是将类的实参及对象的指针进行保存起来,生成一个对象,到执行该函数时,不用显示原来的类执行函数,而是直接执行函数模板生成的对象即可.这样就实现了分离,那么函数模板的关键之处就是如何保存函数参数,及对象地址,返回数据.那么在涉及模板参数时,就至少有三种类型的参数:对象类型,参数类型及返回类型.
另外为了执行函数,就必须包含有函数指针,函数对应的行参及对象指针.而三种类型的参数就可以做为模板参数,后面的具体地址及内容就可以做为函数模板的具体构造函数来实现,为了保存具体的地址及行参,就需要定义模板类的私有成员来进行实现.所以,模板的具体定义(这里假设是单参数的函数模板)如下:
- template <typename ResultType,typename ParamType,class PointerToObj>
- class Functor_t {
- private:
- ParamType param1_;
- PointerToObj* pObj_;
- MemFn_t pMemFn_;
- typedef ResultType (PointerToObj::*MemFn_t)(ParamType);
- public:
- Functor_t(PointerToObj *pObj,MemFn_t pMemFn,ParamType param1):param1_(param1),pMemFn_(pMemFn),pObj_(pObj)
- {
- }
另外还需要进行执行该函数的形式:obj(),直接通过重载运算符函数就可以实现:
- ResultType operator()()
- {
- return (pObj_->*pMemFn_)(param1_);
- }
这样就可以进行调用该函数了:
- A a;
- Functor_t<void,int,A> fn(&a,&A::print,2);
- fn();
但是还有一点不足的是每次都需要指明函数模板的一些参数问题,有些不方便,不过这也是函数模板类的特点,可以对其进行封装采用非类模板:函数的形式来完成,这样就可以不用生成对象就可以进行调用:
- template<class R,class T,class P> Functor_t<R,P,T> Functor(R (T::*f)(P),T* pT,P param)
- {
- return Functor_t<R,P,T>(pT,f,param);
- }
这样在调用时,就不用具体指明参数的类型了:
- Functor(&A::print,&a,2)();
采用了类似方法,可以构造无参数的函数模板,实现如下:
- template <class R,class T>
- class Fun_t
- {
- private:
- R (T::*pmf)();
- T *pT_;
- public:
- Fun_t(R (T::*f)(),T *pT):pmf(f),pT_(pT) {
-
- }
-
- R operator()()
- {
- return ((pT_->*pmf))();
- }
- };
-
- template<class R,class T>
- Fun_t<R,T> Fun(R (T::*f)(),T *pT)
- {
- return Fun_t<R,T>(f,pT);
- }
采用类似方法可以进行扩展至多个参数,其中上面的测试结果如下:
- print(i:2).
- print(i:2).
- no arguments
- print(i:1).
具体测试程序及实现见附件. MemFn.zip
参考资料:
[1] The C++ Programming Language,Bjarne Stroustrup
[2] Modern C++ Design,Andrei Alexandrescu
[3]
[4]