STL学习_仿函数篇

STL学习_仿函数篇

  • 简介

    仿函数,实质是函数对象,是一种具有函数特质的对象。对调用者,它可以像函数一样地被调用;对被调用者,它可以以对象所定义的function call operator扮演函数的实质决策。

    STL算法中,很多算法的实现都是基于两种版本:

    • 版本一表现出最常用(最直观)的某种运算;
    • 版本二表现出最泛化的演算流程,允许用户“以template参数来指定所要采取的策略”。

    版本二是可以允许用户指定任何“操作”,然后将操作当做算法的参数,实现的方法可以将该“操作”(可能拥有数条以上的指令)设计为一个函数,再将函数指针当做算法的一个参数;或是将该“操作”设计为一个所谓的仿函数,再以该仿函数产生一个对象,并以此对象作为算法的一个参数

    函数指针就能够实现版本二的需求,但为什么还需要仿函数?原因:函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求——函数指针无法和STL其他组件搭配,产生更灵活的变化。

    仿函数实质是一个“行为类似函数”的对象。为使其“行为类似函数”,其类别定义中必须自定义(改写、重载)function call运算算子。拥有这样的运算子后,就可以在仿函数的对象后面加上一对小括号,依此来调用仿函数所定义的operator()。

    STL仿函数与STL算法之间的关系如下:

    algorithm(first, last, ..., functorObj)
    {
        functorObj(...)
    }
    // 其中functorObj是STL内建的仿函数,或用户自定义的仿函数,对应定义格式如下:
    template<typename T> class functor
    {
        void operator()(...);
    }
    
  • 分类

    STL仿函数中,按照操作数的个数划分,主要分为一元和二元仿函数;而按其功能划分,主要分为算法运算、关系运算,逻辑运算三大类。

    STL组件中,仿函数是体积最小,观念最简单,实现最容易的一个。但它却扮演一种“策略”角色,可以让STL算法有更灵活的演出。而更灵活的关键在于STL仿函数的可配接性。仿函数为了拥有可配接性,必须定义自己的相应型别(STL的5个型别之一),此型别主要是为了让配接器能够取出,从而获得仿函数的某些信息。相应的型别都只是一些typedef,所有必要操作在编译期就全部完成,对程序的执行效率没有任何影响,不会带来任何额外负担。仿函数的型别主要用来表现函数参数型别和传回值型别。任何仿函数只要拥有了型别,就拥有了配接能力。

  • 源码分析

    下面主要针对STL源码中的仿函数,按仿函数的类别对其进行简单介绍。

    1)一元仿函数

    // unary_function:用来呈现一元函数的参数型别和返回值型别。
    template <class _Arg, class _Result>
    struct unary_function {
      typedef _Arg argument_type;     // 参数型别
      typedef _Result result_type;    // 返回值型别
    };
    

    2)二元仿函数

    // 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;          // 返回值型别
    };  
    

    3)算法类仿函数

    // plus:加法运算
    template <class _Tp>
    struct plus : public binary_function<_Tp,_Tp,_Tp> {
      _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x + __y; }
    };
    // minus:减法运算
    template <class _Tp>
    struct minus : public binary_function<_Tp,_Tp,_Tp> {
      _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x - __y; }
    };
    // multiplies:乘法运算
    template <class _Tp>
    struct multiplies : public binary_function<_Tp,_Tp,_Tp> {
      _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x * __y; }
    };
    // divides:除法运算
    template <class _Tp>
    struct divides : public binary_function<_Tp,_Tp,_Tp> {
      _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x / __y; }
    };
    // modulus:取余运算
    template <class _Tp>
    struct modulus : public binary_function<_Tp,_Tp,_Tp> 
    {
      _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x % __y; }
    };
    // negate:取反运算
    template <class _Tp>
    struct negate : public unary_function<_Tp,_Tp> 
    {
      _Tp operator()(const _Tp& __x) const { return -__x; }
    };
    

    4)证同元素仿函数

    所谓“运算符op的证同元素(identity element),指数值A若与该元素做op运算,会得到A自己。加法的证同元素为0,因为任何元素加上0仍为自己;乘法的证同元素为1,因为任何元素乘以1仍为自己。

    template <class _Tp> inline _Tp identity_element(plus<_Tp>) {
      return _Tp(0);
    }
    // 乘法证同元素。即数值A与1相乘,值为A。
    template <class _Tp> inline _Tp identity_element(multiplies<_Tp>) {
      return _Tp(1);
    }
    

    5)关系运算类仿函数

    // equal_to:相等运算
    template <class _Tp>
    struct equal_to : public binary_function<_Tp,_Tp,bool> 
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
    };
    // not_equal_to:不相等运算
    template <class _Tp>
    struct not_equal_to : public binary_function<_Tp,_Tp,bool> 
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x != __y; }
    };
    // greater:大于运算
    template <class _Tp>
    struct greater : public binary_function<_Tp,_Tp,bool> 
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x > __y; }
    };
    // less:小于运算
    template <class _Tp>
    struct less : public binary_function<_Tp,_Tp,bool> 
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }
    };
    // greater_equal:大于等于运算
    template <class _Tp>
    struct greater_equal : public binary_function<_Tp,_Tp,bool>
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x >= __y; }
    };
    // less_equal:小于等于运算
    template <class _Tp>
    struct less_equal : public binary_function<_Tp,_Tp,bool> 
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x <= __y; }
    };
    

    6)逻辑运算类仿函数

    // logical_and:逻辑And运算
    template <class _Tp>
    struct logical_and : public binary_function<_Tp,_Tp,bool>
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x && __y; }
    };
    // logical_or:逻辑Or运算
    template <class _Tp>
    struct logical_or : public binary_function<_Tp,_Tp,bool>
    {
      bool operator()(const _Tp& __x, const _Tp& __y) const { return __x || __y; }
    };
    // logical_not:逻辑Not运算
    template <class _Tp>
    struct logical_not : public unary_function<_Tp,bool>
    {
      bool operator()(const _Tp& __x) const { return !__x; }
    };
    

    7)证同(identity)、选择(select)、投射(project)类仿函数

    // 证同函数:任何值通过此函数后,不会有任何改变
    template <class _Tp>
    struct _Identity : public unary_function<_Tp,_Tp> {
      const _Tp& operator()(const _Tp& __x) const { return __x; }
    };
    template <class _Tp> struct identity : public _Identity<_Tp> {};
    
    // 选择函数:接受一个pair,传回其第一元素
    template <class _Pair>
    struct _Select1st : public unary_function<_Pair, typename _Pair::first_type> {
      const typename _Pair::first_type& operator()(const _Pair& __x) const {
        return __x.first;
      }
    };
    // 选择函数:接受一个pair,传回其第二元素
    template <class _Pair>
    struct _Select2nd : public unary_function<_Pair, typename _Pair::second_type>
    {
      const typename _Pair::second_type& operator()(const _Pair& __x) const {
        return __x.second;
      }
    };
    template <class _Pair> struct select1st : public _Select1st<_Pair> {};
    template <class _Pair> struct select2nd : public _Select2nd<_Pair> {};
    
    // 投射函数:传回第一参数,忽略第二参数
    template <class _Arg1, class _Arg2>
    struct _Project1st : public binary_function<_Arg1, _Arg2, _Arg1> {
      _Arg1 operator()(const _Arg1& __x, const _Arg2&) const { return __x; }
    };
    // 投射函数:传回第二参数,忽略第一参数
    template <class _Arg1, class _Arg2>
    struct _Project2nd : public binary_function<_Arg1, _Arg2, _Arg2> {
      _Arg2 operator()(const _Arg1&, const _Arg2& __y) const { return __y; }
    };
    template <class _Arg1, class _Arg2> 
    struct project1st : public _Project1st<_Arg1, _Arg2> {};
    template <class _Arg1, class _Arg2>
    struct project2nd : public _Project2nd<_Arg1, _Arg2> {};
    

    仿函数的主要用途是搭配STL算法使用。仿函数的使用方式有两种:

    • 1)定义仿函数实体(对象),然后运行实体(对象),履行函数功能;
    • 2)直接模仿仿函数的临时对象履行函数功能。

    具体使用举例如下(以加法仿函数为例):

    // 方法1
    // 定义仿函数实体(对象)
    plus<int> plusobj;
    // 运用上述实体(对象),履行函数功能
    cout << plustobj(1, 2) << endl;
    
    // 方法2
    cout << plus<int>() (3, 5) << endl;
    
  • 参考文献

    STL源码剖析——侯捷

    STL源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值