模板之泛化仿函数(一)

来源:互联网 发布: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