C++ lambda表达式
写法格式
lambda表达式的写法格式如下:
[capture-list] (parameters) mutable ?-> ret ?{ statement }
各部分的说明为:
[capture-list] : 捕获列表,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。必须要有,即使为空也要写一个[]。
(parameters):参数列表,就是函数的参数列表。如果不需要传参,是可以将()省略的。
mutable:默认情况下,lambda函数是一个const函数,并不支持对捕获到的变量进行修改。mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。mutable是根据需要选择加不加的。
ret:返回值类型,用于追踪函数的返回值类型。没有返回值时此部分可省略。如果返回值的可由编译器推导,也可省略。
{statement}:函数体。可以使用所有捕获到的变量。
因此C++11中最简单的lambda函数为:[]{}; 表示该lambda函数不能做任何事情。
其中,返回值类型后置的写法(->ret)是有迹可循的,返回值类型后置又称跟踪返回类型,允许函数的返回类型在函数声明时不显式指定,而是推断出来。例如(参考:C++返回值类型后置)
int& foo(int& i);
float foo(float& f);
template <typename T>
auto func(T& val) -> decltype(foo(val))
{
return foo(val);
}
捕获列表说明
- [] 不捕获任何变量。
- [&] 捕获父作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
- [=] 捕获父作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
- [=,&foo1, &foo2, ……] 按值捕获外部作用域中所有变量,其中变量foo1、foo2等按引用捕获。
- [val] 按值捕获变量val,且不捕获其他变量。
- [&val] 按引用捕获变量val,且不捕获其他变量。
- [this] 捕获当前类中的 this?指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。
注意事项:
- 父作用域指包含lambda函数的语句块,即lambda表达式所在的作用域。
- 语法上捕捉列表可由多个捕捉项组成,以逗号分割。
- 捕捉列表不允许变量重复传递,否则就会导致编译错误。
- 在块作用域以外的lambda函数捕捉列表必须为空。其中块作用域是指lambda表达式
- 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
- lambda表达式之间不能相互赋值,即使看起来类型相同。
- 由于&表示的是引用捕获,所以就不能用取地址的方式捕获一个地址了。
用法理解
lambda表达式的类型在 C++11 中被称为“闭包类型”,可以理解为“闭包让你可以在一个内层函数中访问到其外层函数的作用域”。从上层用户的角度来看,lambda表达式就相当于是一个匿名函数对象,严格来说是匿名的非枚举类的对象。也就是说,lambda是一个匿名函数对象,故而其类型为匿名类,所以一般情况下很难拿到lambda表达式的类型,一般是通过function包装器等间接地使用lambda表达式。
lambda表达式在底层实现上和模板有些相似,lambda表达式其实是由编译器为我们生成一个类,类内重载了operator()。也就是说C++的lambda表达式本质上就是在编译器在底层帮我们生成了一个仿函数,其中仿函数的类名是lambda+uuid。也就是说,lambda表达式在使用上是一个匿名函数对象,但其实在底层实现上它是一个有名的仿函数,这里需要注意区分。
而捕获列表本质上就是lambda表达式创建的类中成员函数,而捕获的变量默认不支持修改其实是因为底层的仿函数是一个const函数(放在函数名后面的那种)。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!