对于STL中的for_each算法,我们通过一些例子讨论其功能和方便之处
首先介绍下for_each算法,下面是for_each内部具体的实现
template<typename InputIterator, typename Function> Function for_each(InputIterator beg, InputIterator end, Function f) { while(beg != end) f(*beg++); }
for_each带给我们的方便之处:在我们希望遍历一个容器中的所有元素并希望对元素进行操作,如果容器中存放的是一个类的对象或者指针,我们可能希望通过遍历容器让每个元素都完成相同的工作(简单的调用每个元素的成员函数)
基本的是方法可能是直接定义一个迭代器然后遍历整个容器,取值,调用方法或者对元素进行处理,具体的方法如下
vector<int>::iterator iter = coll_01.begin(); for(;iter != coll_01.end();iter ++) { //使用元素进行一些操作 } vector<Student>::iterator iter; for(iter = coll_01.begin(),iter != coll_01.end();iter ++) { //调用对象的成员函数 //(*iter).dosomething }
for_each提供给我们一种方便遍历容器同时可以利用元素进行一些列的操作方法,所以下面我们具体介绍for_each的使用方法
再次看下for_each具体实现
template<typename InputIterator, typename Function> Function for_each(InputIterator beg, InputIterator end, Function f) { while(beg != end) f(*beg++); }
从算法的定义我们可以看出
1.for_each对每一个元素调用f(elem)函数
2.同时返回一个f的副本,同时函数f的返回值都会被忽略
3.复杂度为线性,有多少个元素就调用几次函数f
for_each具体用法
1.让每个元素调用相同的带有一个参数的function函数,容器中的每个元素作为函数的实参
打印所有的元素:
#include <vector> #include <functional> #include <algorithm> #include <string> #include <iostream> using namespace std; template<class T> void PrintValue(T &value)//模板函数输入传入的参数 { cout << value << " "; } int main() { //最简单的for_each与不传入其他参数的函数结合 vector<int> coll_01; for(int i = 0;i < 9;i ++) { coll_01.push_back(i); } //输出内容 cout << "--------简单的不传入参数使用for_each: ----------------" << endl; cout << "输出容器中的元素值: "; for_each(coll_01.begin(),coll_01.end(),PrintValue<int>); cout << endl; return 0; }
运行结果为:
2.for_each与可以接受两个参数的函数结合,PrintElements接受两个参数,模板函数PrintElements_Tem也接受两个参数
void PrintElements(int value,const char *str) { cout << str << value << endl; } template<class T> void PrintElements_Tem(T value,const char *str) { cout << str << value << endl; }
for_each分别于两个函数的结合(此时需要借助另外一个bind2nd进行绑定参数)
//for_each传入参数 cout << "---------------传入参数使用for_each: ------------------" << endl; for_each(coll_01.begin(),coll_01.end(),bind2nd(ptr_fun(PrintElements),"value: ")); cout << endl << endl; cout << "--------------传入参数和模板使用for_each: --------------" << endl; for_each(coll_01.begin(),coll_01.end(),bind2nd(ptr_fun(PrintElements_Tem<int>),"usingTem value: ")); cout << endl << endl;
需要注意的是函数PrintElements和函数PrintElements_Tem第二个参数用const修饰,具体的原因可以从bind2dn的具体实现找到
运行结果为:
3.for_each支持容器中存放的对象或者对象指针调用其成员函数(需要借助mem_fun_ref和mem_fun)
我们定义一个类Student
class Student{ public: Student(string name = "Aldrich",int age = 18):m_stName(name),m_iAge(age) {} void PrintMsg()//C++标准模板库上面说只能调用const类型的函数,现在都可以 const和非const { cout << "My name is " << m_stName << " and I'am " << m_iAge << " old." << endl; } void SayMsg(const char *msg = "Nothing") { cout << m_stName << " says that this is " << msg << endl; } private: string m_stName; int m_iAge; };
如果不借用mem_fun_ref或者mem_fun将会编译不能通过
for_each(vStudent.begin(),vStudent.end(),(&Student::PrintMsg));//将会遇到编译问题,mem_fue将成员函数指针转化为可以作为for_each参数的函数对象
mem_fun_ref与mem_fun的区别主要是容器中存放的内容,如果是对象就是用前者,如果是对象指针就是用mem_fun进行转换
cout << "----for_each和mem_fun_ref或者mem_fun调用成员函数--------" << endl; //mem_fun和mem_fun_ref的区别是调用情况的不同,当你的容器中存放的是对象时使用mem_fun_ref当存放的内容为对象指针的时候使用前者 vector<Student> vStudent; Student stu01("HaAldrich",20); vStudent.push_back(stu01); Student stu2("Freedom",19); vStudent.push_back(stu2); Student stu3("James",24); vStudent.push_back(stu3); for_each(vStudent.begin(),vStudent.end(),mem_fun_ref(&Student::PrintMsg)); cout << endl << endl; cout << "---------借助bind2nd完成调用含有参数的成员函数----------" << endl; for_each(vStudent.begin(),vStudent.end(),bind2nd(mem_fun_ref(&Student::SayMsg),"an Apple")); cout << endl << endl;
运行结果为:
4.使用for_each进行改变元素内容(for_each此时可以称作为变动性算法)
我们将容器中的每个元素加上10然后输出内容,首先定义一个仿函数AddValue
//定义一个仿函数functor帮助我们验证通过for_each可以改变元素的内容,注意使用for_each的时候传入的参数类型为引用 template<class T> class AddValue{ public: AddValue(const T &Value):value(Value){} void operator()(T & elem)const//按照引用方式传递参数 { elem += value; } private: T value; };
cout << "----------------利用for_each改变元素的内容--------------" << endl; cout << "原容器元素为: "; PRINTELEMENT(coll_01); for_each(coll_01.begin(),coll_01.end(),AddValue<int>(10));//让容器中的每个元素都加上一个常数值 cout << "改变过后容器元素为: "; PRINTELEMENT(coll_01); cout << endl << endl;
运行结果为:
5.利用for_each的返回值(参考《STL标准模板库》中的例子)
首先我们定义一个仿函数
//定义一个仿函数functor帮助我们完成如何利用for_each返回值的特性 class MeanValue{ public: MeanValue():m_iNum(0),m_iSum(0) { } void operator()(int elem) { m_iNum ++; m_iSum += elem; } int GetValue() { return m_iSum;//函数返回累加过后的值 } private: int m_iNum; int m_iSum; };
利用for_each的返回值获得经过运算过后的sum的值
cout << "-----------演示for_each可以返回仿函数的功能-------------" << endl; MeanValue tempMeanValue = for_each(coll_01.begin(),coll_01.end(),MeanValue()); cout << "通过for_each的返回仿函数功能得到: " << tempMeanValue.GetValue() << endl; cout << endl << endl;
我们介绍了for_each提供的功能的使用,对于for_each在我们的实际练习中可以尝试使用,对于其中存在的问题,请提出共同交流进步
实践出真知