关于for_each,mem_fun和bind1st在类中的组合使用
考虑有这样的情况,在一个类中有一个容器保存了一些值,现在要遍历这些值并将其作为参数调用这个类的某个成员函数。我们除了直接遍历调用外,也可以用for_each的方法调用,这里介绍了在类内部成员容器遍历调用类内部成员函数的方法。
比如有一个vector容器:
std::vector<int> vct;
你可以用for加迭代器的方式来遍历调用,
for(std::vector<int>::iterator itr = vct.begin(); itr != vct.end();++itr) func(*itr);
|
如果这个func是全局函数的话,我们还可以用stl的for_each泛型算法来调用
std::for_each(vct.begin(),vct.end(),&func); |
但是如果这个func是类成员函数,我们这样写就会有问题。
正确的做法是:对于这个for_each中的第3个函数指针参数,我们可以这样写
std::bind1st(std::mem_fun(&Class::func), this); |
看一下这个函数调用做了什么处理,首先查看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 (mem_fun_t<_Result, _Ty>(_Pm)); }
|
mem_fun有一个参数也就是我们传入的类成员函数指针,这个函数调用mem_fun_t这个函数,继续看stl的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 };
|
这个实际上是定义了一个mem_fun_t类,并将我们mem_fun参数里所传入的函数指针保存在私有成员变量_Pmemfun中。这个类重载了()运算符。在这个重载运算符的函数体中,调用_Pleft参数指针指向的成员函数,也就是_Pmemfun指向的成员函数完成了成员函数的调用过程。
看完了mem_fun,我们再看下std::bind1st的功能。这个函数的功能是将第2个参数作为第一个函数指针参数的第一个值来使用。我们这里调用的是
std::bind1st(std::mem_fun(&Class::func), this);
还记得刚才说的mem_fun_t的()重载运算符吗?这个重载函数的参数也就是我们传入的this,通过bind1st,我们将this指针手动绑定到mem_fun的第一个参数中,完成了函数的功能。
这里是完整的测试代码
#include <vector> #include <iostream> #include <algorithm>
class Test { typedef std::vector<int> INT_VCT; public: Test() { int a[3] = {1,2,3}; vct = INT_VCT(a,a+3); }
void print(int a) { std::cout << a << std::endl; }
void printAll() { std::for_each(vct.begin(),vct.end(),std::bind1st(std::mem_fun(&Test::print), this)); }
private: INT_VCT vct; };
int main() { Test test; test.printAll(); return 0; }
|
对于类成员函数指针有疑惑的地方可以参看我之前的博文:
使用类成员函数指针调用C++成员函数的一种方式
http://blog.csdn.net/duboleon/archive/2010/09/12/5878483.aspx