用法简介

c++11: 也是一种可调用对象。
lambda表达式,它定义了一个匿名函数,并且可以捕获定范围内的变量。

1
2
3
4
auto f = [](int a)->int{
return a + 1;
};
cout << f(10) << endl;

特点:

  • a)是个匿名函数,也可以理解为“可调用的代码单元”,或者理解成未命名的内联函数。
  • b)它也有一个返回类型,一个参数列表,一个函数体
  • c)与函数不同的是,lambda表达式可以在函数内部定义,这个是常规函数做不到的:

格式:
[捕捉列表] (参数列表) ->返回类型函数体};

这是一个返回类型后置这种语法( lambda表达式的返回类型后置是必须的,这个语法就这么规定) ;
因为很多时候lambda表达式返回值特别明显,所以允许lambda表达式返回类型省略,编译器可以自动推导; 但是如果编译器推断不出来的时候需要我们自定义返回类型,否则就会报错。

  • 1.没有参数的时候,参数列表可以省略,甚至()也能省略,所以如下格式都合法
1
2
3
4
auto f1 = []() {return 1;};
auto f2 = [] {return 2;};
cout << f1() << endl;
cout << f2() << endl;
  • 2.捕获列表[]和函数体不能省,必须时刻包含
  • 3.lambda调用方法和普通函数相同,都是使用()这种函数调用运算符;
  • 4.lambda表达式可以不返回任何类型,不返回任何类型就是void:

捕获列表

[捕捉列表]:通过捕获列表来捕获一定范围内的变量,范围是啥意思呢?

1
2
3
4
int i = 0;
auto f1 = [] {
return i;//error 不认识i在哪里
}
  1. [] 不捕获任何变量,但不包括静态局部变量。lambda可以直接使用局部静态变量(局部静态变量是不需要捕获的
  2. [&] 捕获外部作用域中所有变量,并作为引用在函数体内使用
  3. [=] 捕获外部作用域中所有变量,并作为副本(按值)在函数中使用,也就是可以用它的值,但不许给它赋值
  4. [this] 一般用于类中,捕获当前类中this指针,让lambda表达式有和当前类成员函数同样的访问权限
    如果[]中已经使用了&或者=,那么默认就已经使用了this,捕获this的目的就是为了在lmbda中使用成员变量或成员函数
  5. [变量名] 如果有多个变量,则彼此之间用,分隔。[变量名]表示按值捕获变量名代表的变量,同时不捕获其他变量
    [&变量名] 按引用捕获变量名代表的变量,同时不捕获其他变量
  6. [=,&变量名] 按值捕获所有外部变量,但按引用捕获中所指的变量,这里这个=必须写在开头位置,开头这个位置表示默认捕获方式
    也就是说,这个捕获列表,第一个位置表示的是默认捕获方式(隐式捕获方式),后续其他的都是显式捕获方式。
  7. [&,变量名] 按引用来捕获所有外部变量,但按值来捕获变量名所代表的变量,这里这个&必须写在开头位置,

lambda表达式延迟调用分析

1
2
3
4
5
6
int x = 5;
auto f = [=]{
return x;
}
x = 10;
cout << f() << endl;//我们认为是10实际是5

凡是按值捕获的外部变量,在lambda表达式定义的这个时刻,所有这些外部变量值就被复制了一份存储在lambda中

解决办法就是按引用调用

lambda表达式mutable

mutable 易变的
主要用于按值捕获外部变量的时候,加了mutable 后按值捕获的外部变量也可以进行修改了

1
2
3
4
5
int x = 5;
auto f = [=] () mutable {
x = 10;//不报错
return x;
}

lambda表达式类型及存储

一种比较特殊的,匿名的,类类型[闭包类)的对象,也就是定义了一个类类型,又生成一个匿名的该类类型的对象
可以认为它是一个带有operator()的类类型对象,也就是仿函数(函数对象)

lambda表达式这种语法,是我们可以就地定义匿名函数(就地封装短小的功能闭包),我们也可以用std: :function和std::bind来保存和调用lambda表达式