lambda表达式
lambda表达式语法
[capture-list] (parameters) mutable -> return-type {statement}
各部分说明
- 【capture-list】:捕捉列表,编译器通过[]来判断接下来的代码是否是lambda表达式,捕捉列表可以捕捉上下文中的变量宫lambda表达式使用
- (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同()一起省略
- mutable:用来取消捕捉列表中拷贝对象的常属性,使用该修饰符时,参数列表不可以省略
- ->returntype:用来声明函数的返回值类型。没有返回值是此部分可以被省略。返回值类型明确的情况下,也可以省略,由编译器堆返回值类型进行推导
- {statement}:函数体。在该函数内部除了可以使用参数列表中的参数外,还可以使用所有捕获到的变量
注意
在lambda表达式中,只有捕捉列表和函数体是不可以省略外,其他部分都可以被省略,由此,在C++11中最简单的lambda表达式就是:[]{}
,该表达式不能做任何事情
以上就是使用lambda表达式的一个例子
捕捉列表和mutable说明
捕捉列表描述了上下文中哪些数据可以被lambda表达式使用
例如:
#include<iostream>
int main()
{
int a = 2, b = 3;
auto swap = [a, b]()
{
int t = a;
a = b;
b = t;
};
swap();
std::cout << a << ' ' << b << std::endl;
return 0;
}
以上代码中,捕捉列表捕捉了同在main函数中的变量a和变量b,并试图将它们进行交换
当运行时出现以上报错,这是因为捕捉列表捕捉的变量实际上是原变量的拷贝,并且这个拷贝对象是被const所修饰的,当对这个对象进行修改时就会报错。若要修改拷贝的常属性,需要用到mutable
此时代码被修改为
#include<iostream>
int main()
{
int a = 2, b = 3;
auto swap = [a, b]()mutable
{
int t = a;
a = b;
b = t;
};
swap();
std::cout << a << ' ' << b << std::endl;
return 0;
}
因为lambda表达式捕捉列表中的变量是原变量的拷贝,所以对于拷贝变量的修改无法影响到原变量,如果想要修改原变量,则需要传递原变量的引用
#include<iostream>
int main()
{
int a = 2, b = 3;
auto swap = [&a, &b]()
{
int t = a;
a = b;
b = t;
};
swap();
std::cout << a << ' ' << b << std::endl;
return 0;
}
关于捕捉列表的说明
- [var] :用值传递的方式捕捉变量
- [=] : 用值传递的方式捕捉父作用域中的所有变量
- [&var] : 用引用传递的方式捕捉变量
- [&] : 用引用传递的方式捕捉父作用域中的所有变量
- [this] : 表示值传递的方式捕捉当前的this指针
- 父作用域指的是包含lambda表达式的语句块
- 语法上捕捉列表可以由多个捕捉项构成,并用逗号分隔
例如:[=,&a,&b] 表示用引用传递的方式捕捉变量a和变量b,值传递的方式捕捉其他变量
[&,a,this] :用值传递的方式捕捉a变量和this指针,引用传递的方式捕捉其他变量 - 捕捉列表不允许变量重复传递
例如:[=,a],=代表已经用值传递的方式捕捉了所有变量,再用值传递的方式捕捉a就会造成重复 - 在块作用域以外的lambda表达式捕捉列表必须为空
函数对象与lambda表达式
函数对象,又被称为仿函数,就是在类中重载了operator()运算符的类对象
class Greater
{
public:
bool operator()(int a, int b)
{
return a > b;
}
};
int main()
{
Greater g1;
g1(1, 2);//函数对象
//lambda表达式
auto g2 = [](int a, int b)->bool { return a > b; };
g2(1, 2);
return 0;
}
从使用方式上来看,这两者便没有什么差别
我们可以从汇编的角度来看看
在函数对象的汇编中,我们可以看到,当我们运行到g1(1,2)
时,就会跳转到Greater
类中已经重载好的operator()函数中
在lambda表达式中,当运行到g2(1,2)时,程序也会跳转到一个类中的operator()中,(这个类的名字是随机生成的,在不同编译器中命名规则也不同),这就可以印证了C++中lambda表达式其实是用仿函数实现的:生成一个名字随机的类,并重载类中的operator()运算符。
另外,这个类的默认构造是已经被禁用了的,但是拷贝构造并没有被禁用