当前位置:首页 > 芯闻号 > 充电吧
[导读]以前,在lambda表达式没有进入标准的时候,对容器的遍历等涉及到使用函数指针的情况,一般人会懒得使用std::for_each,或std::transform,也许只是一个短短的几句话,却要单独写个

以前,在lambda表达式没有进入标准的时候,对容器的遍历等涉及到使用函数指针的情况,一般人会懒得使用std::for_each,或std::transform,也许只是一个短短的几句话,却要单独写个函数,或函数对象,写的代码反而不如自己用for循环来的快。
但是,C++11引入了lambda表达式后,一切都变的简单了!

1.lambda表达式 lambda表达式是一个匿名函数,用它可以非常方便的表示一个函数对象,先简单说一下lambda表达式,下面这张图表示了C++11中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;……}
如果要传入的参数很多,或者干脆在这个作用域里的所有参数都想用到,可以直接在中括号里使用”=“或”&“ 如下例子,g_bb为一个全局变量,fun3的lambda表达式把所有内容以引用方式传入:
double g_bb = 11.2;
void foo1()
{
    auto f_add = [&](int a,int b)->int{return a+b;};
    std::cout<double{return aa+3;};//此时aa不能进行赋值操作如:aa=7;
    std::cout<double{aa = 7.0;return aa+3;};//此时aa以引用方式传入,可以进行赋值操作如:aa=7,同时修改aa的值;
    std::cout<double{aa = 8.0;g_bb = 15;return aa+3;};//此时aa可以进行赋值操作如:aa=7;,其他在作用域范围的变量都可以以引用方式调用
    std::cout<
输出:

3
8  aa:5
10  aa:7
11  aa:8 g_bb:15

一般也是以这种方式来写[&],简单明了。 lambda表达式先说到这后面在讲std::for_each和std::transform时会有更多例子。 2.std::foreach std::foreach是很经典的算法,但是由于需要用到函数对象,有时候还不如直接for循环方便(暂且不讨论for循环的新表达式写法,目前没多少个编译器支持),例如我有个vector,我要打印出来看看里面有什么内容,经常下意识的就直接成:
std ::vector v ;
v . push_back ( 3);
v . push_back ( 1. 666);
v . push_back ( 4. 5);
v . push_back ( 6. 7);
for( std ::vector ::iterator i =v . begin (); i !=v . end (); ++i )
{
    std ::cout <<*i <<",";
}

std :: vector < double >:: iterator是多么的碍眼的。 还好,C++11把auto升了级,上面那个代码会变成
for( autoi =v . begin (); i !=v . end (); ++i )

用std::foreach(),上面这个就变成

std ::for_each ( v . begin (), v . end (),[ &]( double d ){ std ::cout <

于是,以后凡是要遍历容器,且代码不太长,都可以使用std::foreach加lambda表达式方便实现
为了方便下面的演示,编写一个打印容器内容的函数printElement
template
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<

可以输出序列的内容,如vector内容为(1,2,3,4,5),输出:(1,2,3,4,5) 3.std::transform
当涉及到两个或三个容器的操作,就需要使用std::transform操作 transform有两个重载版本
template 
  OutputIterator transform (InputIterator first1, InputIterator last1,
                            OutputIterator result, UnaryOperation op);

原理如下图所示:



template ;
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)


如果对a序列求log并直接把结果存入a中的话有两种方法 方法1:使用(transform)
 std::cout<<"a=log(a):"<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):"<

输出:

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)
这里,for_each的操作函数以引用方式传入,因此可以实现对自身元素的修改。 从这里可以看出,std::transform是可以实现std::for_each的功能的,也就是说std::transform是std::for_each的扩展
如两个vectorV,W要进行某个运算,如计算U = sin(V) + W,结果存入U;  
std ::vector 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 ;
}

幸好还有auto,要不然,呵呵…… transform的表达形式如下
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 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::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 
#include 
#include 
#include 
#include 
#include "math.h"
double g_bb = 11.2;
void foo1()
{
    auto f_add = [&](int a,int b)->int{return a+b;};
    std::cout<double{return aa+3;};//此时aa不能进行赋值操作如:aa=7;
    std::cout<double{aa = 7.0;return aa+3;};//此时aa以引用方式传入,可以进行赋值操作如:aa=7,同时修改aa的值;
    std::cout<double{aa = 8.0;g_bb = 15;return aa+3;};//此时aa可以进行赋值操作如:aa=7;,其他在作用域范围的变量都可以以引用方式调用
    std::cout<
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< 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<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):"<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):"<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::cout<<"calc c=a+b -> c:";
    printElement(c);

    return 0;
}

写上面这篇文章,主要是因为最近经常使用序列的四则运算,如vector a + vector b,或者进行一些稍微复杂的数学运算,自己封装了一些简化的用法,截取如下:

#define INPUT
#define OUTPUT
namespace Array {
///
/// brief 加一个常数的函数对象,类似于std::plus(),不过此函数对象是用于对一个常数进行加法运算
///
template  struct plus_const : std::binary_function  {
    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
void add(INPUT IT begin,INPUT IT end,T beAddData)
{
    std::transform(begin,end,begin,plus_const(beAddData));
}
///
/// brief 序列加法运算,两个等长序列相加
/// param begin_addfont “加数”序列迭代器的起始
/// param end_addfont “加数”序列迭代器的结尾
/// param begin_addend “被加数”序列迭代器的起始
/// param begin_res 用于存放结果的序列的起始地址
///
template
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());
}
///
/// brief 序列减法运算,两个等长序列相减
/// param begin_addfont “加数”序列迭代器的起始
/// param end_addfont “加数”序列迭代器的结尾
/// param begin_addend “被加数”序列迭代器的起始
/// param begin_res 用于存放结果的序列的起始地址
///
template
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());
}
///
/// brief 序列减法运算,用于序列减去单一一个值
/// param begin 序列迭代器的起始
/// param end 序列迭代器的结尾
/// param beAddData 需要进行减法运算的值
/// note 此操作会直接修改原有序列值
///
template
void minus(INPUT IT begin,INPUT IT end,T beMinusData)
{
    std::transform(begin,end,begin,plus_const(-beMinusData));
}
……
}




本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭