模板之泛化仿函数(一)
来源:互联网 发布:linux find命令详解 编辑:程序博客网 时间:2024/06/05 19:32
1 泛化仿函数的要求
参数个数应该是任意的,参数的型别也应该是任意的。
// 我们的Functor 应该是这样的,Functor 只是一个 wrapper(外覆类) template <typename ResultType, typename TList>class Functor{public: ResultType operator()(); // 转发函数 ResultType operator(Parm1 p1); ResultType operator(Parm1 p1, Parm2 p2); .....};struct T1{ double operator()(int, double) { // .... }};int foo(){ //...}int main(){ Functor<double, TYPELIST_2(int, double)> myFunctor1(T1); myFunctor(4,4.5); // int foo(); 没有参数,返回值为 int Functor<int, NullType> myFunctor2(&foo); myFunctor2();}
2 被 Functor 包覆的多态类 functorImpl
template <typename R, class TList> class FunctorImpl{};template <typename R>class FunctorImpl < R, NullType >{public:virtual R operator()() = 0;virtual FunctorImpl* Clone() const = 0; // 产生FunctorImpl 对象的一份多态拷贝virtual ~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() {}};// 带有 4、5、...更多参数的 FunctorImpl
3 Functor 遵循典型的 handle-body 实现手法
template <typename R, class TList>class Functor{private:typedef FunctorImpl<R, TList> Impl;std::auto_ptr<Impl> spImpl_; // 自动清除资源public: // Functor 具备 value 语义Functor() : spImpl_(0) // default constructor {}Functor(const Functor& rhs) : spImpl_(rhs.spImpl_.get()->Clone()) // copy constructor{}Functor& operator= (const Functor& rhs) // assignment operator{Functor copy(rhs);// swap auto_ptr by handImpl *p = spImpl_.release();spImpl_.reset(copy.spImpl_.release());copy.spImpl_.reset(p);return *this;}explicit Functor(std::auto_ptr<Impl> spImpl) : spImpl_(spImpl) {}public: // 使用 TypeAtNonStrict 模板取得 typelist 中某个位置上的型别,ParmN 是typelist的第N个型别,如果 typelist 元素个数少于 N,获得结果将是 NullTypetypedef TList ParmList;typedef R ResultType;typedef typename TypeAtNonStrict<TList, 0>::Result Parm1;typedef typename TypeAtNonStrict<TList, 1>::Result Parm2;R operator()(){return (*spImpl_)();}R operator()(Parm1 p1){return (*spImpl_)(p1);}R operator()(Parm1 p1, Parm2 p2){return (*spImpl_)(p1, p2);} .....};
4 处理仿函数
任何 class 实体只要定义有 operator(),都是仿函数。 Functor 满足这一定义,所以 Functor 是仿函数。因此“以仿函数 Fun之对象为参数”的 Functor 构造函数,是个“被Fun参数化”的templated 构造函数
template <typename R, class TList>class Functor{ // ... as abovepublic: template <class Fun> Functor(const Fun& fun);};template <typename R, class TList>template <typename Fun> // 注:C++ 将这类代码称为“位于 class 本体之外的 member template 定义式”Functor<R, TList>::Functor(const Fun& fun): spImpl_(new FunctorHandler<Functor, Fun>(fun)){}为了实现这个构造函数,我们需要一个从 FunctorImpl<R, TList>派生而来的class template FunctorHandler ,其中保存了一个型别为 Fun 的对象,并将 operator() 转发给该对象。
// FunctorHandlertemplate <class ParentFunctor, typename Fun>class FunctorHandler: public FunctorImpl < typename ParentFunctor::ResultType,typename ParentFunctor::ParmList >{public:FunctorHandler(const Fun& fun) : fun_(fun) {}FunctorHandler* Clone() const{return new FunctorHandler(*this);}public:typedef typename ParentFunctor::ResultType ResultType;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_;};
struct TestFunctor{void operator()(int i, double d){cout << "TestFunctor::operator()(" << i<< "," << d << ") called." << endl;}};void Test(){ cout << "Test" << endl;}int main(){TestFunctor f;Functor<void, TYPELIST_2(int, double)> cmd(f);cmd(4, 4.5);Functor<void, NullType> cc(&Test); // 这里必须传函数指针而不是函数名cc();}
5 参数和返回型别的转化
const char* TestFunc(double, double){static const char buffer [] = "Hello, world!";return buffer;}int main(){Functor<string, TYPELIST_2(int, int)> cmd3(&TestFunc); // 隐式转换:参数 int -> double cout << cmd3(10, 10).substr(7) << endl; // 返回值 const char* -> std::stringreturn 0;}
6 处理 pointer to member function
// member function 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& pObj, const PointerToMemFn& pMemFn): pObj_(pObj), 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 p1, typename ParentFunctor::Parm2 p2){return ((*pObj_).*pMemFn_)(p1, p2);}private:PointerToObj pObj_;PointerToMemFn pMemFn_;};template <typename R, class TList>class Functor{ // ... as abovepublic: template <class PointerToObj, class PointerToMemFn>Functor(const PointerToObj& pObj, const PointerToMemFn& pMemFn);;};template <typename R, class TList>template <typename PointerToObj, typename PointerToMemFn>Functor<R, TList>::Functor(const PointerToObj& pObj, const PointerToMemFn& pMemFn): spImpl_(new MemFunHandler<Functor, PointerToObj, PointerToMemFn>(pObj, pMemFn)){}class Parrot{public:void Eat(){cout << "Tsk, knick, tsk..." << endl;}void Speak(){cout << "On Captain, My Captain" << endl;}};int main(){// member functionFunctor<void, NullType > cmd1(&geronimo, &Parrot::Eat);Functor<void, NullType> cmd2(&geronimo, &Parrot::Speak);cmd1();cmd2();return 0;}
7 重载函数传给 Functor 的歧义错误
void TestFunction(int i, double d){cout << "TestFunction: " << i<< "," << d << ") called." << endl;}void TestFunction(int i){cout << "TestFunction: " << i << ") called." << endl; }int main(){// overload functionsFunctor<void, TYPELIST_2(int, double)> cmd1(&TestFunction); // error, 无法确定该使用哪一个 TestFunction 版本cmd1(5, 5.5);return 0;}如果你重载 TestFunction,就得想办法消除歧义性。原因是如果 TestFunction 被重载,其名称(符号)所代表的型别就不再有明确定义。
如果出现重载,两种方法可以识别其中某个函数:一使用赋值(assignment),二使用转型(cast)
int main(){ typedef void(*TpFun)(int, double);// method 1: use an assignment//TpFun pF = &TestFunction;TpFun pF = TestFunction; // the same with aboveFunctor<void, TYPELIST_2(int, double)> cmd2(pF);cmd2(4, 4.5);// method 2: use a castFunctor<void, TYPELIST_2(int, double)> cmd3(static_cast<TpFun>(TestFunction));cmd3(5, 5.5);return 0;}
赋值(assignment)和静态转型(static cast)都可以让编译器知道,你感兴趣的实际上是”参数为 int 和 double,返回类型为 void“的那个 TestFunction 函数。
0 0
- 模板之泛化仿函数(一)
- 模板之泛化仿函数(二)
- 泛化仿函数(functors)
- Loki泛化仿函数
- 第五章(泛化仿函数)
- 从零开始学C++之模板(一):函数模板、函数模板特化、重载函数模板、非模板函数重载
- 从零开始学C++之模板(一):函数模板、函数模板特化、重载函数模板、非模板函数重载
- 模板(一)----->函数模板
- 泛化仿函数用法及参数绑定的问题
- part5:仿函数,仿函数类(一)
- 函数模板(一)
- 模板参数类型,仿函数
- C++模版初探之函数模板(一)
- C++模板(一) ----函数模板
- 函数模板特化(一)
- C++之模板与泛型编程(一)——函数模板
- STL之仿函数排序(1)
- C++之仿函数
- 正则表达式—-转义
- 播布客教学视频_C学习笔记_8.1_统计1到100中9的个数(分治)
- __try,__except,__finally,__leave异常模型机
- 播布客教学视频_C学习笔记_8.2_统计1到100中9的个数(函数)
- UI第一课
- 模板之泛化仿函数(一)
- Java获取get请求图片资源
- commons-lang 包,特殊字符处理 StringEscapeUtils
- qsort应用集合
- TQ210裸机编程(4)——按键(中断法)
- 骨牌铺方格
- CLASSPATH的注意事项
- 黑马程序员--字节流、转换流、流操作规律
- 第十四周项目2带姓名的成绩单