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 hand Impl *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,获得结果将是 NullType typedef 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 above public: 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() 转发给该对象。
// FunctorHandler template <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::string return 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 above public: 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 function Functor<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 functions Functor<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 above Functor<void, TYPELIST_2(int, double)> cmd2(pF); cmd2(4, 4.5); // method 2: use a cast Functor<void, TYPELIST_2(int, double)> cmd3(static_cast<TpFun>(TestFunction)); cmd3(5, 5.5); return 0; }
赋值(assignment)和静态转型(static cast)都可以让编译器知道,你感兴趣的实际上是”参数为 int 和 double,返回类型为 void“的那个 TestFunction 函数。