我们知道仿函数是仅重载了括号操作符,且定义了若干相应型别的类。仿函数存在的意义,是为了能提取出仿函数中定义的相应型别,使仿函数能与函数适配器进行配接,而这些相应型别则主要是用来表现函数参数类型与传回值类型。
函数指针因为没有相应型别而不能与STL 中别的组件进行搭配。因此,仿函数的相应型别是一个很重要的因子。
STL 中定义了两个类,分别代表一元仿函数和二元仿函数,其中没有任何数据成员或函数成员,唯有一些型别定义,任何仿函数,按照各自的需求继承其中一个类,便拥有了相应的型别,也就拥有了自动配接能力。具体代码如下:
//unary_function
template<class Arg,class Result>
struct unary_function
{
typedef Arg argument_type;
typedef Result result_type;
};
//binary_function
template<class Arg1,class Arg2,class Result>
struct binary_function
{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
其配接能力体现在能够通过仿函数对象,提取出仿函数对象的参数与返回值类型,以对仿函数对象进行再一次的包装,再次得到一个全新的更外层的仿函数(该新的仿函数属于函数配接器),并可以通过这种方式,像积木般一直堆叠下去。以 binder1st为例:
// binder1st
template<class Operator> //通过下方的 Operator::second_argument_type 等相应型别进行配接,定义了一个新的仿函数
class binder1st : public unary_function < typename Operator::second_argument_type, typename Operator::result_type >
{
protected:
Operator op;
typename Operator::first_argument_type value;
public:
explicit binder1st(const Operator &ops, const typename Operator::first_argument_type & x) :op(ops), value(x){}
typename Operator::result_type operator()(const typename Operator::second_argument_type & x)const
{
return op(value, x);
}
};
template<class Operator,class T>
binder1st<Operator> bind1st(const Operator& op, const T & t)
{
typedef typename Operator::first_argument_type arg1_type;
return binder1st<Operator>(op, arg1_type(t));
}