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 函数。