• STL算法之for_each


      简单来将,仿函数(functor)就是一个重载了"()"运算符的struct或class,利用对象支持operator()的特性,来达到模拟函数调用效果的技术。

       我们平时对一个集合类遍历的时候,例如vector,是这样做的:
    1 for(vector<int>::const_iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
    2 {
    3     //do your whatever you want here
    4 }

    例如下面的代码:

     1 #include <vector>
     2 #include <iostream>
     3 
     4 struct State
     5 {
     6     State( int state ) : m_state( state ){}
     7     ~State() { std::cout << "~State(), m_state=" << m_state << std::endl; }
     8 
     9     void setState( int state ){ m_state = state; }
    10     int getState() const{ return m_state; }
    11 
    12     void print() const { std::cout << "State::print: " << m_state << std::endl; }
    13 
    14 private:
    15     int m_state;
    16 };
    17 
    18 int main()
    19 {
    20     std::vector<State*> vect;
    21 
    22     vect.push_back( new State(0) );
    23     vect.push_back( new State(1) );
    24     vect.push_back( new State(2) );
    25     vect.push_back( new State(3) );
    26 
    27        std::vector<State*>::iterator it( vect.begin() );
    28     std::vector<State*>::iterator ite( vect.end() );
    29     for ( ; it != ite; ++it )
    30     {
    31         (*it)->print();
    32     }
    33     
    34     
    35     system( "pause" );
    36     return 0;
    37 }

    这里的for循环语句有点冗余,想到了std::for_each ,为了使用for_each,我们需要定义一个函数,如下:

    void print( State* pstate )
    {
        pstate->print();
    }

    于是就可以简化为下面代码:
      std::for_each( vect.begin(), vect.end(), &print );

    上面这段代码有点丑陋,看起来不太爽,主要是函数指针的原因。
    在这种应用环境下,C++有仿函数来替代,我们定义一个仿函数,如下:

    struct Printer
    {
        template<typename T> void operator()( T* t ) { t->print(); }
    };

    于是就可以简化为下面代码:
      std::for_each( vect.begin(), vect.end(), Printer() );

    下面,我们初步看下 for_each 的STL源码实现:

    1 template<class InputIterator, class Function>
    2   Function for_each(InputIterator first, InputIterator last, Function f)
    3   {
    4     for ( ; first!=last; ++first ) f(*first);
    5     return f;
    6   }

    它返回f已在算法内部变动过的一个副本。

    f可以是普通函数,也可是仿函数。它的任何返回值都将被忽略。

    其实for_each就是一个模板函数,将for循环语句封装起来,前面两个参数都是迭代器,第三个参数是使用一个函数指针(或仿函数),其功能是对每一个迭代器所指向的值调用仿函数。

    上面代码还是有点冗余,因为为了使用for_each还要单独定义一个函数(或仿函数),不太清爽,
    呵呵,stl早为我们准备好了 mem_fun 模板函数来解决这个一个问题,于是代码再次简化为:

    std::for_each( vect.begin(), vect.end(), std::mem_fun( &State::print ) );

    我们一起看看 mem_fun 的STL源码实现: 

     1 // TEMPLATE FUNCTION mem_fun
     2 template<class _Result,
     3     class _Ty> inline
     4     mem_fun_t<_Result, _Ty> mem_fun(_Result (_Ty::*_Pm)())
     5     {    // return a mem_fun_t functor adapter
     6     return (std::mem_fun_t<_Result, _Ty>(_Pm));
     7     }
     8 
     9 mem_fun 函数实际上是调用 mem_fun_t 函数,我们接着深入看看 mem_fun_t,
    10 
    11 
    12         // TEMPLATE CLASS mem_fun_t
    13 template<class _Result,
    14     class _Ty>
    15     class mem_fun_t
    16         : public unary_function<_Ty *, _Result>
    17     {    // functor adapter (*p->*pfunc)(), non-const *pfunc
    18 public:
    19     explicit mem_fun_t(_Result (_Ty::*_Pm)())
    20         : _Pmemfun(_Pm)
    21         {    // construct from pointer
    22         }
    23 
    24     _Result operator()(_Ty *_Pleft) const
    25         {    // call function
    26         return ((_Pleft->*_Pmemfun)());
    27         }
    28 private:
    29     _Result (_Ty::*_Pmemfun)();    // the member function pointer
    30     };
    31 
    32 将上面这段代码定义的写的我们好看懂一点,如下:
    33 
    34         // TEMPLATE CLASS mem_fun_t
    35 template< typename _Result, typename _Ty >
    36 class mem_fun_t : public unary_function<_Ty *, _Result>
    37 {    
    38     typedef _Result (_Ty::*_Pmemfun)();
    39 public:
    40     explicit mem_fun_t( _Pmemfun& pfunc )
    41         : m_pfun( pfunc )
    42     {    // construct from pointer
    43     }
    44 
    45     _Result operator()(_Ty *_Pleft) const
    46     {    // call function
    47         return ( (_Pleft->*m_pfun)() );
    48     }
    49 
    50 private:
    51     _Pmemfun m_pfun; // the member function pointer
    52 
    53 };

      这样就比较清晰了,定义了仿函数mem_fun_t内部定义了一个类成员函数指针,仿函数构造的时候将函数指针保存起来,当仿函数operator()被调用的时候,就通过与一个类的实例关联起来从而实现了类成员函数的调用。

      其调用流程是这样的,for_each把vector中的元素传送给mem_fun,mem_fun自己产生一个仿函数mem_fun_t,然后仿函数调用其重载的()。

      上述源码还有最后一个没有说明,就是unary_function,直接上源码:

    1 // TEMPLATE STRUCT unary_function
    2 template<class _Arg,
    3     class _Result>
    4     struct unary_function
    5     {    // base class for unary functions
    6     typedef _Arg argument_type;
    7     typedef _Result result_type;
    8     };

    就一个模板结构体。没有数据成员,非常简单。
    最后,定义一个删除指针的仿函数:
    struct DeletePointer
    {
        template<typename T> void operator()( T* ptr ) const { delete ptr; }
    };
    然后调用,就一个逐一删除vector里面的所有元素了。
    std::for_each( vect.begin(), vect.end(), DeletePointer() );

    本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/14080627.html

  • 相关阅读:
    消息路由的构成
    消息的构造
    消息传递通道
    消息传递系统
    EXtJS Ext.data.Model
    oracle coherence介绍及使用
    LINUX下安装和配置WEBLOGIC10.0.3
    WebLogic中"域"的概念
    WebLogic中的一些基本概念
    下属有能力却不服管,你该怎么办?
  • 原文地址:https://www.cnblogs.com/MrLiuZF/p/14080627.html
Copyright © 2020-2023  润新知