「学习笔记」Lambda 表达式

Lambda 表达式因数学中的 λ 演算得名, 直接对应于其中的 lambda 抽象. Lambda 表达式能够捕获作用域中的变量的无名函数对象, 我们可以将其理解为一个匿名的内联函数, 可以用来替换独立函数或者函数对象, 从而使代码更可读. 但是从本质上来讲, Lambda 表达式只是一种语法糖, 因为它能完成的工作也可以用其他复杂的 C++ 语法来实现.


下面是 Lambda 表达式的语法结构.

[capture] (parameters) mutable -> return-type {statement}

capture: 捕获;

parameters: 参数;

mutable: 可变规范;

return-type: 返回类型;

statement: Lambda 表达式的主体;


下面是更高版本的 C++ 的有关 Lambda 表达式的语法.

[capture] (parameters) lambda说明符 约束(可选) {statement}
[capture] {statement}    // (C++23 前)
[capture] lambda说明符 {statement}    // (C++23 起)
[capture] < 模板形参 > 约束(可选) // (C++20 起)
(parameters) lambda说明符 约束(可选) {statement}    // (C++20 起)
[capture] < 模板形参 > 约束(可选) {statement}    // (C++20 起 C++23 前)
[capture] < 模板形参 > 约束(可选) lambda说明符 {statement}    //(C++23 起)

capture 捕获#

捕获 是一个含有零或更多个捕获符的逗号分隔列表, 可以 默认捕获符 开始. 默认捕获符只有

  • &(以引用隐式捕获被使用的自动变量)和
  • =(以复制隐式捕获被使用的自动变量).

当出现任一默认捕获符时, 都能隐式捕获当前对象(*this). 如果隐式捕获它, 那么会始终以引用捕获,即使默认捕获符是 =. 当默认捕获符为 = 时, *this 的隐式捕获被弃用. (C++20 起)

当默认捕获符是 & 时, 后继的简单捕获符不能以 & 开始.

struct S2 { void f(int i); };
void S2::f(int i)
{
    [&]{}; // OK:默认以引用捕获
    [&, i]{}; // OK:以引用捕获,但 i 以值捕获
    [&, &i] {}; // 错误:以引用捕获为默认时的以引用捕获
    [&, this] {}; // OK:等价于 [&]
    [&, this, i]{}; // OK:等价于 [&, i]
}

当默认捕获符是 = 时, 后继的简单捕获符必须以 & 开始, 或者为 *this (C++17 起) 或 this (C++20 起).

struct S2 { void f(int i); };
void S2::f(int i)
{
    [=]{}; // OK:默认以复制捕获
    [=, &i]{}; // OK:以复制捕获,但 i 以引用捕获
    [=, *this]{}; // C++17 前:错误:无效语法
    // C++17 起:OK:以复制捕获外围的 S2
    [=, this] {}; // C++20 前:错误:= 为默认时的 this
    // C++20 起:OK:同 [=]
}

任何捕获符只可以出现一次, 并且名字不能与形参相同:

struct S2 { void f(int i); };
void S2::f(int i)
{
    [i, i] {}; // 错误:i 重复
    [this, *this] {}; // 错误:"this" 重复(C++17)
    [i] (int i) {}; // 错误:形参和捕获的名字相同
}

parameters 参数#

大多数情况下类似于函数的参数列表.

C++14 中, 若参数类型是泛型, 则可以使用 auto 声明类型:

int x[] = {5, 1, 7, 6, 1, 4, 2};
std::sort(x, x + 7, [](int a, int b) { return (a > b); });
for (auto i : x) std::cout << i << " ";

这份代码将打印出 x 数组从大到小排序后的结果.

mutable 可变规范#

利用可变规范, Lambda 表达式的主体可以修改通过值捕获的变量. 若使用此关键字, 则 parameters 不可省略 (即使为空).

一个例子, 使用 capture 捕获字句 中的例子, 来观察 a 的值的变化:

int a = 0; 
auto func = [a]() mutable { ++a; };

此时 lambda 中的 a 的值改变为 1, lambda 外的 a 保持不变.

return-type 返回类型#

用于指定 Lambda 表达式的返回类型. 若没有指定返回类型, 则返回类型将被自动推断 (行为与用 auto 声明返回值的普通函数一致). 具体的, 如果函数体中没有 return 语句, 返回类型将被推导为 void, 否则根据返回值推导. 若有多个 return 语句且返回值类型不同, 将产生编译错误.

auto lam = [](int a, int b) -> int

statement Lambda 主体#

Lambda 主体可包含任何函数可包含的部分。普通函数和 Lambda 表达式主体均可访问以下变量类型:

  • 从封闭范围捕获变量
  • 参数
  • 本地声明的变量
  • 在一个 class 中声明时,若捕获 this,则可以访问该对象的成员
  • 具有静态存储时间的任何变量,如全局变量

大部分资料来自 OI-Wiki.


  1. 该资料来自Lambda表达式(C++11起)-cppreference.com ↩︎

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYQ0cZdz' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片