为何使用Lambda表达式
“几度风雨 几度春秋,风霜雪雨博激流,历尽苦难痴心不改……”
别只顾欣赏音乐啊,你想起了什么?《少年壮志不言愁》?《便衣警察》?刘欢?停,倒过去,倒过去,对,就是《便衣警察》,他们以便衣出现,可以最接近现场,虽然不知道他们是警察,更不知道他们是谁,但是知道有他们。你心里就放心啦,有问题,他们可以以最便捷的方式出手……
在C++11世界里,也有便衣,只不过他们拥有另外一个名字:Lambda表达式。有人说,C++的世界里有inline,有friend,为什么还要Lambda表达呢?作为技术人员,新的东西出现,肯定是为了更方便,更适用,你何不记住一点:学习它,掌握它,使用它,那么它变成了你的忠心管家呢!好吧,好吧,你就是想知道?那好吧,它可以:
- 传值或引用的方式使用本地变量,特别是函数参数比较多时,非常有用;
- 可以随时定义短小精悍的函数;
- 再也不必为如何定义函数名而头痛了;
- 在代码中也不必为想知道一个函数的实现而在文件中跳来跳去了;
- 写多线程程序的时候,不用定义全局变量,不用未加锁而烦恼了。
下面是一个小小的才艺展示,下面有请Lambda表达式掌门get_even.cpp出场:
#include<iostream>
#include <vector>
using namespace std;
int main()
{
int even_cnt = 0;
vector<int> vec;
for(int i=0; i < 10; i++ )
{
vec.push_back(i);
}
for_each(vec.begin(),vec.end(),[&even_cnt](int n){
if(0==n%2)
++even_cnt;
});
cout<<"even number is "<<even_cnt<<endl;
return 0;
}
各位观众,感觉怎么样?掌声喊起来吧,怎么,看不明白!好吧,好吧,别激动,快坐下,我给各位解释一下吧:
该掌门让帮中翘楚施展迷魂大法第一式引用捕获even_cnt变量,又运转传参心法,把vec的心法挑选一遍,然后把适合even_cnt修炼的内功心法传给了even_cnt。
所以当该翘楚表演结束时,你就惊奇地发现,even_cnt站着没动,他的武力值就从0飙升到了4……
掌声不断!喊声也不断!
主持人:你们也想学,那一个一个的上来吧。让该翘楚直接传心功法给你。
观众:我们想学该翘楚的心法。
主持人:掌门,观众不解渴啊,你看?
掌门:那,好吧!那我就把该秘籍公布于世吧。至于能学到几层,那就看个人造化了。
首先,一张内功运转图挂出来了:
- 捕获列表(也是C++规范中的Lambda引出符,在函数的开头)
- 参数列表(可选。和普通函数一样,注意:如果没有参数,可以连()一起省略哦)
- mutable(可选。默认函数是const,使用mutable可以取消函数的常量性。如果有mutable修饰,2步骤不能略)
- 异常 (可选。指定是否抛出异常)
- 返回类型(可选。返回类型)
- 函数体
现在重点介绍capture 指定在可见域范围内适合修炼哪种心法。具体解释如下:
[a,&b] 修炼物理攻击心法a,修炼魔法攻击心法b。
[this] 修炼物理攻击心法的方式捕获 this 指针。
[&] 修炼所有的外部魔法攻击心法。
[=] 修炼所有的外部物理攻击心法。
[] 好吧,五行缺五行,不能修炼任何攻击魔法。
太深奥,没有听懂,好吧,我再解释一下,注意!注意!:
此处物理攻击心法指的是值传递,
魔法攻击心法则指的是引用传递。
问:那我五行俱全,可以修炼任何功法,那还可不可以挑选任一个功法着重修炼呢?
答:你缺心眼啊!所有的都能学,当然不必再着重再修炼某一个啦!
当在一个默认引用[&]捕获列表中,不允许再使用引用指定变量,在默认值传递捕获列表中也适用,不允许再使用值传递指定变量。一个变量或this指针不能捕获语句中出现超过一次。代码说话:
struct S { void f(int i); };
void S::f(int i) {
[&, i]{}; // OK
[&, &i]{}; // ERROR: 引用变量i已经被默认捕获了
[=, this]{}; // ERROR: this已经被默认值传递捕获了
[i, i]{}; // ERROR: 重复指定值传递变量i
}
当你使用捕获列表时,建议注意以下几点,特别是在多线程中使用的时候:
- 引用捕获可以修改外部变量,而值捕获则不可以
- 引用捕获可以返回外部变量的更新,而值捕获则不能
- 引用捕获引进外部变量的整个生存期的依赖,而值捕获则没有