C++ lambda表达式

发布时间:2023年12月20日

写法格式

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 中使用当前类的成员函数和成员变量。

注意事项:

  1. 父作用域指包含lambda函数的语句块,即lambda表达式所在的作用域。
  2. 语法上捕捉列表可由多个捕捉项组成,以逗号分割。
  3. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
  4. 在块作用域以外的lambda函数捕捉列表必须为空。其中块作用域是指lambda表达式
  5. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
  6. lambda表达式之间不能相互赋值,即使看起来类型相同。
  7. 由于&表示的是引用捕获,所以就不能用取地址的方式捕获一个地址了。

用法理解

lambda表达式的类型在 C++11 中被称为“闭包类型”,可以理解为“闭包让你可以在一个内层函数中访问到其外层函数的作用域”。从上层用户的角度来看,lambda表达式就相当于是一个匿名函数对象,严格来说是匿名的非枚举类的对象。也就是说,lambda是一个匿名函数对象,故而其类型为匿名类,所以一般情况下很难拿到lambda表达式的类型,一般是通过function包装器等间接地使用lambda表达式。

lambda表达式在底层实现上和模板有些相似,lambda表达式其实是由编译器为我们生成一个类,类内重载了operator()。也就是说C++的lambda表达式本质上就是在编译器在底层帮我们生成了一个仿函数,其中仿函数的类名是lambda+uuid。也就是说,lambda表达式在使用上是一个匿名函数对象,但其实在底层实现上它是一个有名的仿函数,这里需要注意区分。

而捕获列表本质上就是lambda表达式创建的类中成员函数,而捕获的变量默认不支持修改其实是因为底层的仿函数是一个const函数(放在函数名后面的那种)。

文章来源:https://blog.csdn.net/m0_73759312/article/details/134917027
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。