仿函数functor和function adapters

         所谓的functor就是使用起来像函数一样的东西,如果你针对某个class进行operator() 【function call操作符】重载,它就成为一个仿函数,至于要成为一个可配接的仿函数,还需要做一些额外的努力。

使functor具备配接能力

         为了拥有配接能力,每一个仿函数都必须定义自己的相应型别,就像迭代器如果要融入整个STL大家庭,也必须依照规定定义自己的5个相应型别一样。这些型别是为了让配接器能够获取相关仿函数的信息,相应的型别都只是一些typedef,其定义了函数的参数型别及返回值类型。

         为了方便起见,stl_function.h中定义了两个classes,unary_function和binary_function,分别代表一元仿函数和二元仿函数。只要按需求选择继承某一个class,变自动拥有了那些相应型别,也就自动拥有了配接能力。相关源码如下:

template 
struct unary_function {
 typedef _Arg argument_type;
 typedef _Result result_type;
};

template 
struct binary_function {
 typedef _Arg1 first_argument_type;
 typedef _Arg2 second_argument_type;
 typedef _Result result_type;
}; 

stl中的function adapter

         具有配接能力的class,就能够和配接器一起使用了。一些常用的配接器如下:

bind1st, bind2nd, not1, not2, ptr_fun, mem_fun,men_fun_ref, mem_fun1, mem_fun1_ref,其中bind1st和bind2nd用于绑定函数的第一个参数和第二个参数,not1和not2分别适用于一元函数和二元函数。以bind1st为例,我们可以通过其源码进一步了解配接能力的概念:

template 
class binder1st
  :public unary_function {
protected:
 _Operation op;
 typename _Operation::first_argument_type value;
public:
 binder1st(const _Operation& __x,
           const typename _Operation::first_argument_type& __y)
     : op(__x), value(__y) {}
 typename _Operation::result_type
 operator()(const typename _Operation::second_argument_type& __x)const {
   return op(value, __x);
  }
};
 
template 
inline binder1st<_Operation>
bind1st(const _Operation& __fn, const_Tp& __x)
{
 typedef typename _Operation::first_argument_type _Arg1_type;
 return binder1st<_Operation>(__fn, _Arg1_type(__x));
}

ptr_fun, mem_fun, mem_fun_ptr解析

         比较容易混淆的是ptr_fun,mem_fun, mem_fun_ptr三个仿函数,下面进行说明:

1) ptr_fun:将函数指针进行包装,使其具有配接能力,其源码如下:

template 
class pointer_to_unary_function : publicunary_function<_Arg, _Result> {
protected:
 _Result (*_M_ptr)(_Arg);    //封装了函数指针,继承了unary_function,具有配接能力
public:
 pointer_to_unary_function() {}
  explicitpointer_to_unary_function(_Result (*__x)(_Arg)) : _M_ptr(__x) {}
 _Result operator()(_Arg __x) const { return _M_ptr(__x); }
};
 
template 
inline pointer_to_unary_function<_Arg,_Result> ptr_fun(_Result (*__x)(_Arg))
{
  return pointer_to_unary_function<_Arg,_Result>(__x);
}

p.s:这是一元函数的形式,stl还重载了二元函数的ptr_fun,这边不列举了,有兴趣的参考stl_function.h。

2) mem_fun与men_fun_ref:用于将成员函数当做仿函数来使用,使成员函数可以搭配各种泛型算法。当容器元素为T&或T*,而我们又以虚函数作为仿函数,便可以由此实现多态调用。

其区别在于函数实例对象类型不同,如果是T&类型,则使用mem_fun_ref;如果是T*类型,则使用mem_fun。

下面列举源码加以说明(以非const类型为例):

template 
class mem_fun_t : publicunary_function<_Tp*,_Ret> {
public:
 explicit mem_fun_t(_Ret (_Tp::*__pf)()) : _M_f(__pf) {}  //封装了成员函数指针
 _Ret operator()(_Tp* __p) const { return (__p->*_M_f)(); }   //实例对象为指针类型
private:
 _Ret (_Tp::*_M_f)();
};
 
template 
inline mem_fun_t<_Ret,_Tp>mem_fun(_Ret (_Tp::*__f)())
  {return mem_fun_t<_Ret,_Tp>(__f); }
 
template 
class mem_fun_ref_t : public unary_function<_Tp,_Ret>{
public:
 explicit mem_fun_ref_t(_Ret (_Tp::*__pf)()) : _M_f(__pf) {}
 _Ret operator()(_Tp& __r) const { return (__r.*_M_f)(); }    //实例对象为引用类型
private:
 _Ret (_Tp::*_M_f)();
};
 
template 
inline mem_fun_ref_t<_Ret,_Tp>mem_fun_ref(_Ret (_Tp::*__f)())
  {return mem_fun_ref_t<_Ret,_Tp>(__f); }

下面是关于上述三个函数使用的一个实例:

vector v;  //指针可实现多态

vector v;  //引用可实现多态,但无法通过编译, 原因是stl不支持“引用语意”(referencesemantics)

vectorv;  //不能实现多态

class Shape
{
public:
       Shape() {cout << "Shape construct" << endl;}
       virtual ~Shape() {cout << "Shape destuct" < vec;
       vec.push_back(new Rect);
       vec.push_back(new Circle);
       for_each(vec.begin(), vec.end(), mem_fun(&Shape::display));  //应使用mem_fun,因为实例对象是Shape*
                  
       for(vector::iterator iter = vec.begin(); iter !=vec.end(); ++iter)
       {
                cout < vec1;    //无法实现多态
       vec1.reserve(3);
       Rect rect1;
       vec1.push_back(rect1);
       Circle circle1;
       vec1.push_back(circle1);
       for_each(vec1.begin(), vec1.end(), mem_fun_ref(&Shape::display));   //应使用mem_fun_ref,因为实例对象是Shape
 
       //vector vec2; //无法通过编译
       return 0;
}

你可能感兴趣的:(STL)