C++11 lambda表达式在for_each和transform算法下的使用
但是,C++11引入了lambda表达式后,一切都变的简单了!
1.lambda表达式
-
Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示一引用的方式;‘=’表明以值传递的方式捕获,除非专门指出。
-
Lambda表达式的参数列表
-
Mutable 标识(可以没有)
-
异常标识(可以没有)
-
返回值,如果没有,可以不写
-
“函数”体,也就是lambda表达式需要进行的实际操作
下面看看几个lambda表达式的例子
void print(int a){……}上面函数lambda表达式为:
[](int a){……}上面这个是无返回值的例子,下面这个是有返回值的例子
int add(int a,int b){……}上面函数lambda表达式为:
[](int a,int b)->int{……}当需要引入其他变量的时候,如有个类的成员变量需要引用或者函数局部变量这种情况下可以显示声明需要引入的变量
如成员变量:
double m_result;
函数:
void foo(int a,double b) { …… use(m_result); }其lambda表达式可以表示为
[m_result](int a,int b){……use(m_result);}如果lambda表达式需要修改m_result的值,可以以引用方式传递进去
[&m_result](int a,int b){……m_result = 12.1;……}
double g_bb = 11.2; void foo1() { auto f_add = [&](int a,int b)->int{return a+b;}; std::cout<<f_add(1,2);//3 std::cout<<std::endl; double aa = 5.0; auto fun = [aa]()->double{return aa+3;};//此时aa不能进行赋值操作如:aa=7; std::cout<<fun(); std::cout<<" aa:"<<aa<<std::endl;//8 aa:5 auto fun2 = [&aa]()->double{aa = 7.0;return aa+3;};//此时aa以引用方式传入,可以进行赋值操作如:aa=7,同时修改aa的值; std::cout<<fun2(); std::cout<<" aa:"<<aa<<std::endl;//10 aa:7 auto fun3 = [&]()->double{aa = 8.0;g_bb = 15;return aa+3;};//此时aa可以进行赋值操作如:aa=7;,其他在作用域范围的变量都可以以引用方式调用 std::cout<<fun3(); std::cout<<" aa:"<<aa<<" g_bb:"<<g_bb<<std::endl;//11 aa:8 }输出:
3 8 aa:5 10 aa:7 11 aa:8 g_bb:15
2.std::foreach
std ::vector <double>v ; v . push_back ( 3); v . push_back ( 1. 666); v . push_back ( 4. 5); v . push_back ( 6. 7); for( std ::vector <double>::iterator i =v . begin (); i !=v . end (); ++i ) { std ::cout <<*i <<","; }
for( autoi =v . begin (); i !=v . end (); ++i )
用std::foreach(),上面这个就变成
std ::for_each ( v . begin (), v . end (),[ &]( double d ){ std ::cout <<d <<",";});
template<typename Container> void printElement(Container& v) { std::cout<<"("; for(auto i = v.begin();i != v.end();++i) { std::cout<<*i; if(i != v.end() - 1) std::cout<<","; } std::cout<<")"; std::cout<<std::endl; }
3.std::transform
template <class InputIterator, class OutputIterator, class UnaryOperation> OutputIterator transform (InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperation op);
原理如下图所示:
template <class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>; OutputIterator transform (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binary_op);原理如下图所示:
如需要求序列a的log,结果存入c
//求a的log存入c a.clear();b.clear();c.clear(); for(auto i(1);i<10;++i){ a.push_back(i); } std::transform(a.begin(),a.end(),std::back_inserter(c),[](double d)->double{return log(d);}); std::cout<<"a:"; printElement(a);// std::cout<<"c:"; printElement(c);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722)
std::cout<<"a=log(a):"<<std::endl<<"a:"; printElement(a); std::transform(a.begin(),a.end(),a.begin(),[](double d)->double{return log(d);}); std::cout<<"after a:"; printElement(a);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722)输出:
a=log(a): a:(1,2,3,4,5,6,7,8,9) after a:(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722)
方法2:使用(for_each)
std::cout<<"a=log(a):"<<std::endl<<"a:"; printElement(a); std::for_each(a.begin(),a.end(),[](double& d){d = log(d);}); std::cout<<"after a:"; printElement(a);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722)
输出:
a=log(a): a:(1,2,3,4,5,6,7,8,9) after a:(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722)
std ::vector <double>v , w , u ; v . push_back ( 3); v . push_back ( 1.666); v . push_back ( 4.5); v . push_back ( 6.7); w . push_back ( 3); w . push_back ( 1.666); w . push_back ( 4.5); w . push_back ( 6.7); for( autoi =v . begin (), j =w . begin (), k =u . begin (); i !=v . end (), j !=w . end (), k !=u . end ();++i ,++j ,++k ) { *k =sin (*i )+*j ; }
std ::transform ( v . begin (), v . end (), w . begin (), u . begin () ,[&]( double a , double b )->double{ return sin ( a )+b ; } );
使用std::transform可以比较方便的实现序列容器的四则运算
stl提供了plus,multiplies,divides,modulus,negate等函数对象,方便实现加减乘除等运算,具体见:http://www.cplusplus.com/reference/functional/plus/
如实现两序列的加法运算,不必写lambda表达式,直接使用stl的std::plus即可,如:
实现vector<double> A,B,计算C = A+B
a.clear(); b.clear(); c.clear(); for(int i(1);i<10;++i) { a.push_back(i); b.push_back(i*10); } std::cout<<"calc c=a+b:"<<std::endl<<"a:"; printElement(a); std::cout<<"b:"; printElement(b); std::transform(a.begin(),a.end(),b.begin(),std::back_inserter(c),std::plus<double>()); std::cout<<"calc c=a+b -> c:"; printElement(c);
输出:
calc c=a+b: a:(1,2,3,4,5,6,7,8,9) b:(10,20,30,40,50,60,70,80,90) calc c=a+b -> c:(11,22,33,44,55,66,77,88,99)
代码:
#include <iostream> #include <functional> #include <algorithm> #include <vector> #include <iterator> #include "math.h" double g_bb = 11.2; void foo1() { auto f_add = [&](int a,int b)->int{return a+b;}; std::cout<<f_add(1,2);//3 std::cout<<std::endl; double aa = 5.0; auto fun = [aa]()->double{return aa+3;};//此时aa不能进行赋值操作如:aa=7; std::cout<<fun(); std::cout<<" aa:"<<aa<<std::endl;//8 aa:5 auto fun2 = [&aa]()->double{aa = 7.0;return aa+3;};//此时aa以引用方式传入,可以进行赋值操作如:aa=7,同时修改aa的值; std::cout<<fun2(); std::cout<<" aa:"<<aa<<std::endl;//10 aa:7 auto fun3 = [&]()->double{aa = 8.0;g_bb = 15;return aa+3;};//此时aa可以进行赋值操作如:aa=7;,其他在作用域范围的变量都可以以引用方式调用 std::cout<<fun3(); std::cout<<" aa:"<<aa<<" g_bb:"<<g_bb<<std::endl;//11 aa:8 } template<typename Container> void printElement(Container& v) { std::cout<<"("; for(auto i = v.begin();i != v.end();++i) { std::cout<<*i; if(i != v.end() - 1) std::cout<<","; } std::cout<<")"; std::cout<<std::endl; } int main() { foo1(); std::vector<double> a,b,c; a.push_back(3); a.push_back(1.666); a.push_back(4.5); a.push_back(6.7); b.push_back(3); b.push_back(1.666); b.push_back(4.5); b.push_back(6.7); for ( std :: vector < double >:: iterator i = a . begin (); i != a . end ();++ i ) { std::cout<<*i<<",";//3,1.666,4.5,6.7, } std::cout<<std::endl; std::for_each(a.begin(),a.end(),[&](double d){std::cout<<d<<",";});//3,1.666,4.5,6.7, std::cout<<std::endl; c.resize(a.size()); for (auto i=a.begin(),j =b.begin(),k = c.begin(); i!=a.end (),j!=b.end(),k!=c.end();++i,++j,++k) { *k = sin(*i)+*j; } std::transform(a.begin(),a.end(),b.begin(),c.begin() ,[&](double i,double j)->double{return sin(i)+j;}); printElement(c);//(3.14112,2.66147,3.52247,7.10485) a.clear();b.clear();c.clear(); for(auto i(1);i<10;++i){ a.push_back(i); } //求a的log存入c std::cout<<"c=log(a):"<<std::endl<<"a:"; printElement(a); std::transform(a.begin(),a.end(),std::back_inserter(c),[](double d)->double{return log(d);}); std::cout<<"c:"; printElement(c);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722) b = a; std::cout<<"a=log(a):"<<std::endl<<"a:"; printElement(a); std::transform(a.begin(),a.end(),a.begin(),[](double d)->double{return log(d);}); std::cout<<"after a:"; printElement(a);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722) a = b; std::cout<<"a=log(a):"<<std::endl<<"a:"; printElement(a); std::for_each(a.begin(),a.end(),[](double& d){d = log(d);}); std::cout<<"after a:"; printElement(a);//(0,0.693147,1.09861,1.38629,1.60944,1.79176,1.94591,2.07944,2.19722) a.clear(); b.clear(); c.clear(); for(int i(1);i<10;++i) { a.push_back(i); b.push_back(i*10); } std::cout<<"calc c=a+b:"<<std::endl<<"a:"; printElement(a); std::cout<<"b:"; printElement(b); std::transform(a.begin(),a.end(),b.begin(),std::back_inserter(c),std::plus<double>()); std::cout<<"calc c=a+b -> c:"; printElement(c); return 0; }
写上面这篇文章,主要是因为最近经常使用序列的四则运算,如vector a + vector b,或者进行一些稍微复杂的数学运算,自己封装了一些简化的用法,截取如下:
#define INPUT #define OUTPUT namespace Array { /// /// \brief 加一个常数的函数对象,类似于std::plus<T>(),不过此函数对象是用于对一个常数进行加法运算 /// template <class T> struct plus_const : std::binary_function <T,T,T> { plus_const(const T& data){m_data = data;} T operator() (const T& x) const {return x+m_data;} T m_data; }; /// /// \brief 序列加法运算,用于序列加上单一一个值 /// \param begin 序列迭代器的起始 /// \param end 序列迭代器的结尾 /// \param beAddData 需要进行加法运算的值 /// \note 此操作会直接修改原有序列值 /// template<typename T,typename IT> void add(INPUT IT begin,INPUT IT end,T beAddData) { std::transform(begin,end,begin,plus_const<T>(beAddData)); } /// /// \brief 序列加法运算,两个等长序列相加 /// \param begin_addfont “加数”序列迭代器的起始 /// \param end_addfont “加数”序列迭代器的结尾 /// \param begin_addend “被加数”序列迭代器的起始 /// \param begin_res 用于存放结果的序列的起始地址 /// template<typename T,typename IT> void add(INPUT IT begin_addfont,INPUT IT end_addfont,IT begin_addend,IT begin_res) { std::transform(begin_addfont,end_addfont,begin_addend,begin_res ,std::plus<T>()); } /// /// \brief 序列减法运算,两个等长序列相减 /// \param begin_addfont “加数”序列迭代器的起始 /// \param end_addfont “加数”序列迭代器的结尾 /// \param begin_addend “被加数”序列迭代器的起始 /// \param begin_res 用于存放结果的序列的起始地址 /// template<typename T,typename IT> void minus(INPUT IT begin_minusfont,INPUT IT end_minusfont,IT begin_minusend,IT begin_res) { std::transform(begin_minusfont,end_minusfont,begin_minusend,begin_res ,std::minus<T>()); } /// /// \brief 序列减法运算,用于序列减去单一一个值 /// \param begin 序列迭代器的起始 /// \param end 序列迭代器的结尾 /// \param beAddData 需要进行减法运算的值 /// \note 此操作会直接修改原有序列值 /// template<typename T,typename IT> void minus(INPUT IT begin,INPUT IT end,T beMinusData) { std::transform(begin,end,begin,plus_const<T>(-beMinusData)); } …… }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。