C++ STL 学习 :for_each与仿函数(functor)(一)
By zieckey( All right reserved!)
先看wikipedia定义:
A function object, also called a functor, functional, or functionoid,[1] is a computer programming construct allowing an object to be invoked or called like it was an ordinary function, usually with the same syntax.
简单来将,仿函数(functor)就是一个重载了"()"运算符的struct或class,利用对象支持operator()的特性,来达到模拟函数调用效果的技术。
我们平时对一个集合类遍历的时候,例如vector,是这样做的:
for(vector::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 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++ ); }
|
其实for_each就是一个模板函数,将for循环语句封装起来,前面两个参数都是迭代器,第三个参数是使用一个函数指针(或仿函数),
其功能是对每一个迭代器所指向的值调用仿函数。之前觉得for_each挺神秘的,其实看看源码也挺简单的。呵呵。
上面代码还是有点冗余,因为为了使用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 void operator()( T* ptr ) const { delete ptr; }
};
然后调用,就一个逐一删除vector里面的所有元素了。
std::for_each( vect.begin(), vect.end(), DeletePointer() );
源码:
#include <vector> #include <iostream> #include <algorithm> #include <functional>
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; };
void print( State* pstate ) { pstate->print(); }
struct Printer { template<typename T> void operator()( T* t ) { t->print(); } };
struct DeletePointer { template<typename T> void operator()( T* ptr ) const { delete ptr; } };
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(); }
std::for_each( vect.begin(), vect.end(), &print ); std::for_each( vect.begin(), vect.end(), Printer() ); std::for_each( vect.begin(), vect.end(), std::mem_fun( &State::print ) ); std::for_each( vect.begin(), vect.end(), DeletePointer() ); vect.clear();
system( "pause" ); return 0; }
|
参考链接:
1、