一、lambda优点
- 减少命名烦恼
- 支持泛型编程
二、lambda什么时候用?
- 简单、使用频率低的操作
lambda可以理解为一个未命名的内联函数,内联函数的语句应该足够简单,否则会影响效率。两种情况最好使用函数而不是lambda表达式,第一种语句较复杂、多;第二种则是调用频繁。 - 解除算法特定谓词限制
一些算法要求可调用对象必须为特定谓词(find_if
接受单一参数谓词),使用捕获列表可以降低谓词元数
三、lambda的定义
定义一个lambda等效于定义一个新的未命名类类型,向一个函数传递lambda也就是传递一个lambda对象,使用auto定义变量等效于定义了对应的对象。格式如下:
[capture_list](parameter_list)->return type{fucntion body}
函数体内部可以无条件使用外部的全局变量、作用域内的静态变量,需要捕获才能使用外部局部变量,捕获的变量放在中括号内[我是外部局部变量]
,和函数参数一样,捕获变量类型可以是引用或者值捕获。值捕获的变量是不能在函数内进行修改的,这是因为:
- 结果上看,值捕获的变量即使修改了也无法输出
- 效率上看,值捕获的变量应该设置为常量(事实上也是)以提高效率
事实上,值传递在函数上常见,从结果上看,虽然起不到任何作用,但是我可以复用这个空间。所以,lambda表达式在函数体前加入关键字mutable
去掉常量属性。
为了简洁,如果表达式参数列表为空,小括号可省略。
ff = [i]() {i *= 2; };//not allow
ff = [i]() mutable{i *= 2; };//allow
如果捕获的变量较多,捕获列表将会相当冗长。因此C++提供了隐式捕获的符号,它代表着没有显式捕获的所有变量的默认行为,用符号=
没有特别声明的一律按值捕获形式,用符号&
表示没有特殊声明的一律按照引用捕获。
-
parameter_list:参数列表;
-
return type:返回类型;
-
function boby:函数体。
捕获形式 | 含义 |
---|---|
[] | 空捕获(全局和局部静态仍然可见) |
[names] | 一个逗号分隔的捕获变量列表 |
& | 隐式引用捕获,引用捕获所有外部变量 |
= | 隐式值捕获,值捕获所有外部变量 |
[&,identifier_list] | 除了identifier_list外的所有外部变量都为引用 |
[=,identifier_list] | 除了identifier_list外的所有外部变量都为值 |
注意事项:
- 尽可能减少捕获量,减少出错的可能;
- 捕获指向性的对象(指针、迭代器和引用)应该特别注意指向对象是否存在;
- 值捕获是快照,引用捕获是地址;
- lambda有返回值。函数体内没有
return
默认返回void
;单个return
出口,lambda自行推断(不用自己写返回类型);多个return
出口,加上-->return type
- this指针,是一个low-level属性的指针,因此不能引用捕获,只能值捕获。
- this指针,你可以使用[=]或者[this]来捕获,[*this]在C++17后可以使用
四、lambda调用
使用调用运算符()
五、lambda引用捕获和值捕获的捕获时刻
引用捕获在调用时进行捕获,而值捕获则是在定义之时进行捕获。
int main()
{
int a=22;
auto f=[a](){cout<<a<<endl; };//值捕获,网页快照,内容不变。
auto ff=[&a]{cout<<a<<endl;};//引用捕获,访问地址,内容会调整。
f();
a++;
ff();
f();
}
输出结果分别是:22 23 22
[1]《C++ primer 5th》
[2] 你为什么要用lambda表达式?理解它你就知道了
[3] [C++ 11 Lambda表达式] /DswCnblog/p/
[4] 全局变量和静态变量都不需要捕获,因为对函数体可见。类成员也需要捕获。