简单来将,仿函数(functor)就是一个重载了"()"运算符的struct或class,利用对象支持operator()的特性,来达到模拟函数调用效果的技术。
  我们平时对一个集合类遍历的时候,例如vector,是这样做的:

for(vector<int>::const_iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
{//do your whatever you want here
}

例如下面的代码:
#include <vector>
#include <iostream>struct State
{State( int state ) : m_state( state ){}~State() { std::cout << "~State(), m_state=" << m_state << std::endl; }void setState( int state ){ m_state = state; }int getState() const{ return m_state; }void print() const { std::cout << "State::print: " << m_state << std::endl; }private:int m_state;
};int main()
{std::vector<State*> vect;vect.push_back( new State(0) );vect.push_back( new State(1) );vect.push_back( new State(2) );vect.push_back( new State(3) );std::vector<State*>::iterator it( vect.begin() );std::vector<State*>::iterator ite( vect.end() );for ( ; it != ite; ++it ){(*it)->print();}system( "pause" );return 0;
}

这里的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源码实现:

 // TEMPLATE FUNCTION for_each

template<class _InIt,class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func){    // perform function for each element
_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Func);_CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));_CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));for (; _ChkFirst != _ChkLast; ++_ChkFirst)_Func(*_ChkFirst);return (_Func);}上面的代码看起来挺晕菜的,这里给出 effective STL 里面的一个实现,简单明了:template< typename InputIterator, typename Function >
Function for_each( InputIterator beg, InputIterator end, Function f ) {while ( beg != end )f( *beg++ );
} // TEMPLATE FUNCTION for_each

template<class _InIt,class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func){    // perform function for each element
_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Func);_CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));_CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));for (; _ChkFirst != _ChkLast; ++_ChkFirst)_Func(*_ChkFirst);return (_Func);}上面的代码看起来挺晕菜的,这里给出 effective STL 里面的一个实现,简单明了:template< typename InputIterator, typename Function >
Function for_each( InputIterator beg, InputIterator end, Function f ) {while ( beg != end )f( *beg++ );
}

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

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

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

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

       // TEMPLATE FUNCTION mem_fun
template<class _Result,class _Ty> inlinemem_fun_t<_Result, _Ty> mem_fun(_Result (_Ty::*_Pm)()){    // return a mem_fun_t functor adapterreturn (std::mem_fun_t<_Result, _Ty>(_Pm));}mem_fun 函数实际上是调用 mem_fun_t 函数,我们接着深入看看 mem_fun_t,// TEMPLATE CLASS mem_fun_t
template<class _Result,class _Ty>class mem_fun_t: public unary_function<_Ty *, _Result>{    // functor adapter (*p->*pfunc)(), non-const *pfunc
public:explicit mem_fun_t(_Result (_Ty::*_Pm)()): _Pmemfun(_Pm){    // construct from pointer
        }_Result operator()(_Ty *_Pleft) const{    // call functionreturn ((_Pleft->*_Pmemfun)());}
private:_Result (_Ty::*_Pmemfun)();    // the member function pointer
    };将上面这段代码定义的写的我们好看懂一点,如下:// TEMPLATE CLASS mem_fun_t
template< typename _Result, typename _Ty >
class mem_fun_t : public unary_function<_Ty *, _Result>
{    typedef _Result (_Ty::*_Pmemfun)();
public:explicit mem_fun_t( _Pmemfun& pfunc ): m_pfun( pfunc ){    // construct from pointer
    }_Result operator()(_Ty *_Pleft) const{    // call functionreturn ( (_Pleft->*m_pfun)() );}private:_Pmemfun m_pfun; // the member function pointer

};

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

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

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

 // TEMPLATE STRUCT unary_function
template<class _Arg,class _Result>struct unary_function{    // base class for unary functions
    typedef _Arg argument_type;typedef _Result result_type;};

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

C++ STL 学习 :for_each与仿函数(functor)相关推荐

  1. STL学习笔记(仿函数)

    仿函数(Functors) 仿函数(functor),就是使一个类的使用看上去象一个函数.其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了. 例如我们定义一个 ...

  2. STL学习_配接器篇

    STL学习_配接器篇 定义 配接器(Adapter)在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色.它事实上是一种设计模式.即将一个class的接口转换为另一个class的接口,使原本因接 ...

  3. c语言 谓词,C++ 谓词(predicate) 与 仿函数 ( functor (function object))

    #谓词与函数对象 谓词 predicate C++ 标准定义谓词如下: The Predicate parameter is used whenever an algorithm expects a ...

  4. C++中的仿函数functor

    引子 先考虑一个简单的例子:假设有一个vector<string>,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码: bool LessThan5 ...

  5. C++ STL学习笔记

    C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...

  6. C++STL学习笔记(4) 分配器(Allocator)

    在前面的博客<C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍>中,简单的介绍了分配器再STL的容器中所担当的角色,这一节对STL六大部件之一的分配器进行详细 ...

  7. C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍

    继续学习侯捷老师的课程! 在前面的博客<C++ STL学习笔记(2) 容器结构与分类>中介绍了STL中常用到的容器以及他们的使用方法,在我们使用容器的时候,背后需要一个东西支持对内存的使用 ...

  8. STL学习——RB-tree篇

    STL学习--RB-tree篇 简介 RB-tree(红黑树)是一棵平衡二叉搜索树,它需要满足以下规则: 1)每个节点不是红色就是黑色: 2)根节点为黑色: 3)如果节点为红,其子节点必须为黑: 4) ...

  9. 【STL学习指南】STL的入门学习指南

    目录 STL 学习指南 一. STL基础 二. C++ STL 容器 1 序列式容器 1.1 array 1.2 vector 1.3 deque 1.4 list 2 关联式容器 2.1 map 2 ...

  10. C++入门、STL学习、二级C++等

    跟侯捷学CPP 跟侯捷学CPP的个人空间_哔哩哔哩_Bilibili <C++ Primer 第五版> <C++ Primer 第五版>_哔哩哔哩_bilibili C++教程 ...

最新文章

  1. Office 365系列(7)------ Exchange 2013与Office 365 Hybrid混合部署Step by Step参考
  2. Cassandra使用 —— 一个气象站的例子
  3. aop对请求后端的参数修改_Spring Aop 修改目标方法参数和返回值
  4. php 单元测试 麻烦,php – 正确的单元测试
  5. java-Integer的自动装箱与拆箱
  6. SAP Spartacus 启动时 Chrome 里观察到的 product.js
  7. js 延迟几秒执行_深入研究 Node.js 的回调队列
  8. pygame小游戏(接球小游戏)
  9. Class 18 - 1 图形验证码的识别
  10. git安装 perl ubuntu_Ubuntu系统上安装Git
  11. (Trie树)leetcode208: Implement Trie,79:Word Search,DFS与BFS(python实现),212:Word Search2...
  12. Scratch3.0学习视频链接
  13. 实现MySQL读写分离---maxscale代理服务器配置(详解)
  14. 问卷数据分析(SPSSSPSS Modeler)
  15. 伺服电机驱动器编程用c语言吗,伺服电机如何编程
  16. QT Andriod U盘检测
  17. set, setenv, export的区别
  18. PapeDeading:Deep into Regularity: A Simple but Effective Method for Chinese Named Entity Recognition
  19. 【论文晨读】一种移动机器人全局最优路径规划算法 孟 偲2008
  20. 基于EasyNVR摄像机流媒体服务器实现RTSP或Onvif监控摄像头Web无插件化直播监控

热门文章

  1. CCNA学习要点,希望能对初学者有帮助
  2. 浅谈URL生成方式的演变
  3. Hard lockup occurs due to an infinite loop encountered in distribute_cfs_runtime()
  4. FRR BGP协议分析4 -- 路由更新(1)
  5. 分析“关于Linux内核引入的accept_local参数的一个问题”
  6. OpenCV图像直方图案例
  7. Linux Scheduling Domains
  8. SylixOS allwinner h6 链接脚本
  9. Ensemble Learning方法总结
  10. 自学资料总结(持续更新)