您的位置:首页 > 编程语言 > C语言/C++

C++中的仿函数

2016-06-13 13:08 281 查看
  端午放假回家,无意间拾起侯捷的
<<STL源码剖析>>
,之前一直看的不太懂,没想到今天翻到仿函数(factors)一章,竟有所收获,而且刚好与上一章讲述的函数指针很有关联,遂赶紧记录下来。

  在algorithm算法库中有一个for_each函数用于对某个可迭代对象进行某种操作,行为类似于python中的map函数。

  其核心代码如下:

template<class _InIt,
class _Fn1> inline
void _For_each(_InIt _First, _InIt _Last, _Fn1& _Func)
{   // perform function for each element
for (; _First != _Last; ++_First)
_Func(*_First);
}


我们注意到其实for_each只是对for语句的一层封装,简化书写。但是其实值得我们思考的地方在于放在for循环中的是
_Func(*_First);
那么从程序的角度来说,它只关心_Func能够做()操作就可以了。所以我们习惯性的会传入一个函数指针,简单的一点就是C++11标准中的lambda函数,但是其中类通过重载operator()也可以像函数一样被调用,这就是被我们忽略的仿函数。百度百科定义为:使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为。

  在stl中提供了大量有用的仿函数,比如plus,minus,multiplies,divides,modulus,equal_to,not_equal_to,greater…很多很多,根据传入的参数的个数我们可以分为只需要接受一个参数的仿函数(unary_function)和需要接收两个参数的仿函数(binary_function)。其源码实现基本类似:

template<class _Arg,
class _Result>
struct unary_function //只需要接受一个参数的仿函数,返回值类型为_Result
{   // base class for unary functions
typedef _Arg argument_type;
typedef _Result result_type;
};

template<class _Arg1,
class _Arg2,
class _Result>
struct binary_function //需要接受两个参数的仿函数,返回值类型为_Result
{   // base class for binary functions
typedef _Arg1 first_argument_type;
typedef _Arg2 second_argument_type;
typedef _Result result_type;
};


  比如 bit_not(按位取反)操作只需要接收一个参数:

template<class _Ty = void>
struct bit_not
: public unary_function<_Ty, _Ty>
{   // functor for unary operator~
_Ty operator()(const _Ty& _Left) const
{   // apply operator~ to operand
return (~_Left);
}
};


比如最经典的我们在申明一个map时,其中map是一个需要3个泛型参数的类,其声明为

template<class _Kty,
class _Ty,
class _Pr = less<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty> > >
class map..... //省略不重要代码


  我们知道map是一个有序容器,那么到底是以如何的顺序呢?就在于第二个泛型参数
class _Pr = less<_Kty>
,其默认值为
less<_Kty>
,less是stl内置的用于两者比较大小的仿函数,也就是map是按照key由小到大的顺序排列的。less的实现源码如下:

template<class _Ty = void>
struct less
: public binary_function<_Ty, _Ty, bool>
{   // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{   // apply operator< to operands
return (_Left < _Right);
}
};


  那么如果我们想把map的排列顺序改为由大到小,甚至建立自己的排序规则都只要依葫芦画瓢重写一个仿函数然后声明map时盖住默认的less行为即可。

  STL大致分为六大模块:容器(container),算法(algorithm),迭代器(iterator),仿函数(functor),配接器(adapter),配置器(allocator)。其中仿函数是体积最小,观念最简单,但是在stl算法的搭配中起到了非常重要的作用,这是与简单的lambda或者指针函数所不同的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 仿函数