C++ STL 学习 :for_each与仿函数(functor)
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() );
vect.push_back( new State() );
vect.push_back( new State() );
vect.push_back( new State() ); std::vector<State*>::iterator it( vect.begin() );
std::vector<State*>::iterator ite( vect.end() );
for ( ; it != ite; ++it )
{
(*it)->print();
} system( "pause" );
return ;
}
这里的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> inline
mem_fun_t<_Result, _Ty> mem_fun(_Result (_Ty::*_Pm)())
{ // return a mem_fun_t functor adapter
return (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 function
return ((_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 function
return ( (_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)的更多相关文章
- STL学习笔记(仿函数)
仿函数(Functors) 仿函数(functor),就是使一个类的使用看上去象一个函数.其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了. 例如我们定义一个 ...
- 侯捷STL学习(11)--算仿+仿函数+适配器
layout: post title: 侯捷STL学习(十一) date: 2017-07-24 tag: 侯捷STL --- 第三讲 标准库内核分析-算法 标准库算法形式 iterator分类 不同 ...
- STL仿函数functor
一:仿函数functor介绍 尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数的方法,那就是函数对象. functor,翻译成函数对象,伪函数,算符,是重载了“()”操作符的 ...
- Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value
Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value */--> div.org-src-container ...
- STL学习小结
STL就是Standard Template Library,标准模板库.这可能是一个历史上最令人兴奋的工具的最无聊的术语.从根本上说,STL是一些"容器"的集合,这些" ...
- STL学习总结
STL就是Standard Template Library,标准模板库.这可能是一个历史上最令人兴奋的工具的最无聊的术语.从根本上说,STL是一些"容器"的集合.这些" ...
- 标准模板库(STL)学习指南之sort排序
对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算法也基本固定下来,不需要你再去花费心思 ...
- C++ 谓词(predicate) 与 仿函数 ( functor (function object))
谓词与函数对象 谓词 predicate C++ 标准定义谓词如下: The Predicate parameter is used whenever an algorithm expects a f ...
- function call操作符(operator()) 仿函数(functor)
主要是需要某种特殊的东西来代表一整组操作 代表一整组操作的当然是函数,过去通过函数指针实现 所以STL算法的特殊版本所接受的所谓条件或策略或一整组操作都以仿函数的形式呈现 #include <i ...
随机推荐
- myeclipse2013以及以后的最新版各种破解(其实就是获取活跃码而已)
当你下到最新版的myeclipse-blue的时候你是否会为注册激活而烦恼呢,别担心,其实激活也就那么点事儿,请遵循我如下做法就可以了: 免积分下载破解地址 http://download.csdn. ...
- Java里的if else嵌套语句例子
import java.util.Scanner; public class if_else3 { public static void main(String[] args) { Scanner s ...
- Hibernate映射之OneToOne(第二篇)
这是在项目中实际遇到的一个问题,纠结了很久.一开始参考mkyong的 ,两边都写OneToOne ,后来查看了一下项目经理在原来一些模块中的写法. 学习一下: 首先是E-R图: 一个货品可以进行多次 ...
- JQuery学习(选择器-简单-animated)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...
- 【Python自动化运维之路Day7】
1. configparser模块 import configparser config = configparser.ConfigParser() #先把config应用一下configparser ...
- SQLSERVER复制优化之一《改变包大小》
SQLSERVER复制优化之一<改变包大小> 自从搭了复制之后以为可以安枕无忧了,谁不知问题接踵而来 这次遇到的问题是丢包,不知道情况的读者可以先看一下我之前写的一篇<SQLSERV ...
- 使用 sqlcmd 运行 Transact-SQL 脚本文件
在数据恢复时遇到问题:bat文件批处理的指导文档 https://msdn.microsoft.com/zh-cn/library/ms170572%28v=sql.120%29.aspx
- property和attribute的区别
property是指类向外提供的数据区域.而attribute则是描述对象在编译时或运行时属性的,分为固有型和用户自定义型,其中用户自定义型可以利用Reflection在运行期获取.这两者是有本质区别 ...
- atitit.标准时间格式 互相转换 秒数 最佳实践
atitit.标准时间格式 互相转换 秒数 最佳实践 例如00:01:19 转换为秒数 79,,and互相转换 一个思路是使用div 60 mod...不过麻烦的... 更好的方法是使用stamp ...
- fir.im Weekly - 我回来了
Hey, 大家好,距离 fir.im 新版上线已匆忙过去一周多的时间,新版的fir正在慢慢稳定优化中,感谢大家的反馈与支持!后续我们将上线 FAQ 帮助中心,如还有疑问请邮件至 help@fir.im ...