Linux
Linux software install
Google repo的使用
Vector AP StartApplication编译脚本解析
Yocto的cmake版本升级
不能自动安装的解决方式
S32G-BSP35.0-SDK使用方法
S32G从SDK生成文件系统的制作过程
Linux Samba设置
Linux添加双网卡
S32G USB-Redirector安装指南
VS code自动生成Doxygen格式注释
Linux下使用多线程下载
使用pandoc 生成带中文的pdf
minicom无法输入的问题解决办法
使用 systemd unit 添加一条路由规则
CMake 教程
步骤 1:基本起点
步骤 2:添加lib库
步骤 3:为库添加使用要求
步骤 4:添加生成器表达式
步骤 5:安装和测试
步骤 6:添加支持测试仪表板
步骤 7: 添加系统内省
步骤 8:自定义命令和生成的文
步骤 9:打包安装程序
步骤 10:选择静态库或共享库
步骤 11:添加导出配置
步骤 12:打包 Debug 和 Release
添加虚拟网卡
Vector AP 去掉防篡改校验
Vector AP startapplication编译与使用
Vector AP问题汇总
Vector AP大型项目开发流程
Vector AP EM
Vector AP 最简单的开发示例
Linux kernel 版本降级
Vector AP StartApplicaiton
startappplication-machine-design
startapplicaiton-machine-integration
amsr-vector-fs-em-executionmanager-design
amsr-vector-fs-em-executionmanager
Vector AP 复杂模型的开发
第一章 Machine和MachineDesign
第二章 Execute Manager
第三章 Log
第四章 State Manager
第五章 State Manager 源码的理解
第六章 Someip daemon
第七章 IPC Service Discovery Daemon
crond的使用方法
解决蓝牙鼠标在 Ubuntu 中单位时间内断开的问题
VPS服务器自建教程
v2rayA的客户端使用配置
GDB调试指南入门篇:揭开程序运行世界的神秘面纱
GDB调试指南高级篇:成为调试专家,掌控程序的命运
Linux安装PyQt5并配置Qt Designer
ADB 命令大全
GoogleTest(一)
GoogleTest(二)简单的TEST宏
GoogleTest(三)简单类函数测试
C++ Template
1. 函数模板
2. 类模板
3. 非类型模板参数
软件版本号规范
EPOLL
C++手札
C++ 使用{}初始化有哪些好处?
现代 C++ decltype 深入解析
函数对象(functor)
Linux性能剖析:CPU、内存、网络与I/O压力测试
AP StateManager
C++ Lambda表达式
C++ 中的Lambda表达式
Lambda 表达式语法
Lambda 表达式的示例
手动发送UDP数据包
pyqt5生成的UI界面不能输入中文
自己搭建repo镜像
摄影
Sony仿富士PP值设置
诗词歌赋
本文档使用 MrDoc 发布
-
+
首页
C++ 中的Lambda表达式
## 本文内容 1. [相关文章](#related-articles) 2. [Lambda 表达式的各个部分](#parts-of-a-lambda-expression) 3. [constexpr Lambda 表达式](#constexpr-lambda-expressions) 4. [Microsoft 专用](#microsoft-specific) 5. [另请参阅](#see-also) 在 C++ 11 和更高版本中,Lambda 表达式(通常称为 Lambda)是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象(闭包)的简便方法。 Lambda 通常用于封装传递给算法或异步函数的少量代码行。 本文将提供 Lambda 的定义、将它与其他编程技术进行比较。 其中介绍了各自的优点,并提供了一些基本示例。 ## 相关文章 + [Lambda 表达式与函数对象](https://learn.microsoft.com/zh-cn/cpp/cpp/lambda-expression-syntax?view=msvc-170) + [使用 Lambda 表达式](https://learn.microsoft.com/zh-cn/cpp/cpp/examples-of-lambda-expressions?view=msvc-170) + [constexpr Lambda 表达式](https://learn.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-constexpr?view=msvc-170) ## Lambda 表达式的各个部分 下面是一个简单的 Lambda,它作为第三个参数传递给 `std::sort()` 函数: ```cpp #include <algorithm> #include <cmath> void abssort(float* x, unsigned n) { std::sort(x, x + n, // Lambda expression begins [](float a, float b) { return (std::abs(a) < std::abs(b)); } // end of lambda expression ); } ``` 此图显示了 Lambda 语法的组成部分:  1. capture 子句(在 C++ 规范中也称为 Lambda 引导。) 2. 参数列表(可选)。 (也称为 Lambda 声明符) 3. mutable 规范(可选)。 4. exception-specification(可选)。 5. trailing-return-type(可选)。 6. Lambda 体。 Lambda 表达式示例为 `[=]() mutable throw() -> int { return x+y; }` 其中 `[=]` 是捕获子句,在 C++ 规范中也称为 Lambda 引入符。 参数列表会使用括号`()`。 可变关键字是可选的。 throw() 是可选的异常规范。 -> int 是可选的尾置返回类型。 Lambda 正文由语句构成(语句用大括号括起来),或者返回 x+y; ### capture 子句 Lambda 可在其主体中引入新的变量(用 C++14),它还可以访问(或“捕获”)周边范围内的变量。 Lambda 以 capture 子句开头。 它指定捕获哪些变量,以及捕获是通过值还是通过引用进行的。 有与号 (`&`) 前缀的变量通过引用进行访问,没有该前缀的变量通过值进行访问。 空 capture 子句 `[ ]` 指示 lambda 表达式的主体不访问封闭范围中的变量。 可以使用默认捕获模式来指示如何捕获 Lambda 体中引用的任何外部变量:`[&]` 表示通过引用捕获引用的所有变量,而 `[=]` 表示通过值捕获它们。 可以使用默认捕获模式,然后为特定变量显式指定相反的模式。 例如,如果 lambda 体通过引用访问外部变量 `total` 并通过值访问外部变量 `factor`,则以下 capture 子句等效: ```cpp [&total, factor] [factor, &total] [&, factor] [=, &total] ``` 使用默认捕获时,只有 Lambda 体中提及的变量才会被捕获。 如果 capture 子句包含默认捕获 `&`,则该 capture 子句的捕获中没有任何标识符可采用 `&identifier` 形式。 同样,如果 capture 子句包含默认捕获 `=`,则该 capture 子句没有任何捕获可采用 `=identifier` 形式。 标识符或 **`this`** 在 capture 子句中出现的次数不能超过一次。 以下代码片段给出了一些示例: ```cpp struct S { void f(int i); }; void S::f(int i) { [&, i]{}; // OK [&, &i]{}; // ERROR: i preceded by & when & is the default [=, this]{}; // ERROR: this when = is the default [=, *this]{ }; // OK: captures this by value. See below. [i, i]{}; // ERROR: i repeated } ``` 捕获后跟省略号是一个包扩展,如以下[可变参数模板](https://learn.microsoft.com/zh-cn/cpp/cpp/ellipses-and-variadic-templates?view=msvc-170)示例中所示: ```cpp template<class... Args> void f(Args... args) { auto x = [args...] { return g(args...); }; x(); } ``` 要在类成员函数体中使用 Lambda 表达式,请将 **`this`** 指针传递给 capture 子句,以提供对封闭类的成员函数和数据成员的访问权限。 Visual Studio 2017 版本 15.3 及更高版本(在 [`std:c++17`](https://learn.microsoft.com/zh-cn/cpp/build/reference/std-specify-language-standard-version?view=msvc-170) 模式及更高版本中可用):可以通过在 capture 子句中指定 **`*this`** 通过值捕获 **`this`** 指针。 通过值捕获会将整个闭包复制到调用 Lambda 的每个调用站点。 (闭包是封装 Lambda 表达式的匿名函数对象)。当 Lambda 在并行或异步操作中执行时,通过值捕获非常有用。 它在某些硬件体系结构(如 NUMA)上特别有用。 有关展示如何将 Lambda 表达式与类成员函数一起使用的示例,请参阅 [Lambda 表达式示例](https://learn.microsoft.com/zh-cn/cpp/cpp/examples-of-lambda-expressions?view=msvc-170)中的“示例:在方法中使用 Lambda 表达式”。 在使用 capture 子句时,建议你记住以下几点(尤其是使用采取多线程的 Lambda 时): + **引用捕获可用于修改外部变量,而值捕获却不能实现此操作。 (**`mutable`** 允许修改副本,而不能修改原始项。)** + **引用捕获会反映外部变量的更新,而值捕获不会。** + **引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。 当 Lambda 以异步方式运行时,这一点尤其重要。 如果在异步 Lambda 中通过引用捕获局部变量,该局部变量将很容易在 Lambda 运行时消失。 代码可能会导致在运行时发生访问冲突。** ### 通用捕获 (C++14) 在 C++14 中,可在 Capture 子句中引入并初始化新的变量,而无需使这些变量存在于 Lambda 函数的封闭范围内。 初始化可以任何任意表达式表示;且将从该表达式生成的类型推导新变量的类型。 借助此功能,你可以从周边范围捕获只移动的变量(例如 `std::unique_ptr`)并在 Lambda 中使用它们。 ```cpp pNums = make_unique<vector<int>>(nums); //... auto a = [ptr = move(pNums)]() { // use ptr }; ``` ### 参数列表 Lambda 既可以捕获变量,也可以接受输入参数。 参数列表(在标准语法中称为 Lambda 声明符)是可选的,它在大多数方面类似于函数的参数列表。 ```cpp auto y = [] (int first, int second) { return first + second; }; ``` 在 C++14 中,如果参数类型是泛型,则可以使用 **`auto`** 关键字作为类型说明符。 此关键字将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 **`auto`** 实例等效于一个不同的类型参数。 ```cpp auto y = [] (auto first, auto second) { return first + second; }; ``` Lambda 表达式可以将另一个 Lambda 表达式作为其自变量。 有关详细信息,请参阅 [Lambda 表达式示例](https://learn.microsoft.com/zh-cn/cpp/cpp/examples-of-lambda-expressions?view=msvc-170)一文中的“高阶 Lambda 表达式”。 由于参数列表是可选的,因此在不将自变量传递到 Lambda 表达式,并且其 Lambda 声明符不包含 exception-specification、trailing-return-type 或 **`mutable`** 的情况下,可以省略空括号。 ### mutable 规范 通常,Lambda 的函数调用运算符是 const-by-value,但对 **`mutable`** 关键字的使用可将其取消。它不产生 mutable 数据成员。 利用 **`mutable`** 规范,Lambda 表达式的主体可以修改通过值捕获的变量。 本文后面的一些示例将展示如何使用 **`mutable`**。 ### 异常规范 你可以使用 **`noexcept`** 异常规范来指示 Lambda 表达式不会引发任何异常。 与普通函数一样,如果 Lambda 表达式声明 **`noexcept`** 异常规范且 Lambda 体引发异常,Microsoft C++ 编译器将生成警告 [C4297](https://learn.microsoft.com/zh-cn/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4297?view=msvc-170),如下所示: ```auto // throw_lambda_expression.cpp // compile with: /W4 /EHsc int main() // C4297 expected { []() noexcept { throw 5; }(); } ``` 有关详细信息,请参阅[异常规范 (throw)](https://learn.microsoft.com/zh-cn/cpp/cpp/exception-specifications-throw-cpp?view=msvc-170)。 ### 返回类型 将自动推导 Lambda 表达式的返回类型。 无需使用 [`auto`](https://learn.microsoft.com/zh-cn/cpp/cpp/auto-cpp?view=msvc-170) 关键字,除非指定了 trailing-return-type。 trailing-return-type 类似于普通函数或成员函数的 return-type 部分。 但是,返回类型必须跟在参数列表的后面,你必须在返回类型前面包含 trailing-return-type 关键字 **`->`**。 如果 Lambda 体仅包含一个返回语句,则可以省略 Lambda 表达式的 return-type 部分。 或者,在表达式未返回值的情况下。 如果 lambda 体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。 否则,编译器会将返回类型推导为 **`void`**。 下面的示例代码片段说明了这一原则: ```auto auto x1 = [](int i){ return i; }; // OK: return type is int auto x2 = []{ return{ 1, 2 }; }; // ERROR: return type is void, deducing // return type from braced-init-list isn't valid ``` lambda 表达式可以生成另一个 lambda 表达式作为其返回值。 有关详细信息,请参阅 [Lambda 表达式示例](https://learn.microsoft.com/zh-cn/cpp/cpp/examples-of-lambda-expressions?view=msvc-170)中的“高阶 Lambda 表达式”。 ### Lambda 体 Lambda 表达式的 Lambda 体是一个复合语句。 它可以包含普通函数或成员函数体中允许的任何内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型: + 从封闭范围捕获变量,如前所述。 + 参数。 + 本地声明变量。 + 类数据成员(在类内部声明并且捕获 **`this`** 时)。 + 具有静态存储持续时间的任何变量(例如,全局变量)。 以下示例包含通过值显式捕获变量 `n` 并通过引用隐式捕获变量 `m` 的 lambda 表达式: ```cpp // captures_lambda_expression.cpp // compile with: /W4 /EHsc #include <iostream> using namespace std; int main() { int m = 0; int n = 0; [&, n] (int a) mutable { m = ++n + a; }(4); cout << m << endl << n << endl; } ``` ```shell 5 0 ``` 由于变量 `n` 是通过值捕获的,因此在调用 lambda 表达式后,变量的值仍保持 `0` 不变。 **`mutable`** 规范允许在 Lambda 中修改 `n`。 Lambda 表达式只能捕获具有自动存储持续时间的变量。 但是,可以在 Lambda 表达式体中使用具有静态持续存储时间的变量。 以下示例使用 `generate` 函数和 lambda 表达式为 `vector` 对象中的每个元素赋值。 lambda 表达式将修改静态变量以生成下一个元素的值。 ```cpp void fillVector(vector<int>& v) { // A local static variable. static int nextValue = 1; // The lambda expression that appears in the following call to // the generate function modifies and uses the local static // variable nextValue. generate(v.begin(), v.end(), [] { return nextValue++; }); //WARNING: this isn't thread-safe and is shown for illustration only } ``` 有关详细信息,请参阅 [generate](https://learn.microsoft.com/zh-cn/cpp/standard-library/algorithm-functions?view=msvc-170#generate)。 下面的代码示例使用上一示例中的函数,并添加了使用 C++ 标准库算法 `generate_n` 的 Lambda 表达式的示例。 该 lambda 表达式将 `vector` 对象的元素指派给前两个元素之和。 使用了 **`mutable`** 关键字,使 Lambda 表达式主体可以修改 Lambda 表达式通过值捕获的外部变量 `x` 和 `y` 的副本。 由于 lambda 表达式通过值捕获原始变量 `x` 和 `y`,因此它们的值在 lambda 执行后仍为 `1`。 ```cpp // compile with: /W4 /EHsc #include <algorithm> #include <iostream> #include <vector> #include <string> using namespace std; template <typename C> void print(const string& s, const C& c) { cout << s; for (const auto& e : c) { cout << e << " "; } cout << endl; } void fillVector(vector<int>& v) { // A local static variable. static int nextValue = 1; // The lambda expression that appears in the following call to // the generate function modifies and uses the local static // variable nextValue. generate(v.begin(), v.end(), [] { return nextValue++; }); //WARNING: this isn't thread-safe and is shown for illustration only } int main() { // The number of elements in the vector. const int elementCount = 9; // Create a vector object with each element set to 1. vector<int> v(elementCount, 1); // These variables hold the previous two elements of the vector. int x = 1; int y = 1; // Sets each element in the vector to the sum of the // previous two elements. generate_n(v.begin() + 2, elementCount - 2, [=]() mutable throw() -> int { // lambda is the 3rd parameter // Generate current value. int n = x + y; // Update previous two values. x = y; y = n; return n; }); print("vector v after call to generate_n() with lambda: ", v); // Print the local variables x and y. // The values of x and y hold their initial values because // they are captured by value. cout << "x: " << x << " y: " << y << endl; // Fill the vector with a sequence of numbers fillVector(v); print("vector v after 1st call to fillVector(): ", v); // Fill the vector with the next sequence of numbers fillVector(v); print("vector v after 2nd call to fillVector(): ", v); } ``` Output ```shell vector v after call to generate_n() with lambda: 1 1 2 3 5 8 13 21 34 x: 1 y: 1 vector v after 1st call to fillVector(): 1 2 3 4 5 6 7 8 9 vector v after 2nd call to fillVector(): 10 11 12 13 14 15 16 17 18 ``` 有关详细信息,请参阅 [generate\_n](https://learn.microsoft.com/zh-cn/cpp/standard-library/algorithm-functions?view=msvc-170#generate_n)。 ## `constexpr` Lambda 表达式 Visual Studio 2017 版本 15.3 及更高版本(在 [`/std:c++17`](https://learn.microsoft.com/zh-cn/cpp/build/reference/std-specify-language-standard-version?view=msvc-170) 模式和更高版本中可用):在常量表达式中允许初始化捕获或引入的每个数据成员时,可以将 Lambda 表达式声明为 **`constexpr`**(或在常量表达式中使用它)。 ```cpp int y = 32; auto answer = [y]() constexpr { int x = 10; return y + x; }; constexpr int Increment(int n) { return [n] { return n + 1; }(); } ``` 如果 Lambda 结果满足 **`constexpr`** 函数的要求,则 Lambda 是隐式的 **`constexpr`**: ```cpp auto answer = [](int n) { return 32 + n; }; constexpr int response = answer(10); ``` 如果 Lambda 是隐式或显式的 **`constexpr`**,则转换为函数指针将生成 **`constexpr`** 函数: ```cpp auto Increment = [](int n) { return n + 1; }; constexpr int(*inc)(int) = Increment; ``` ## Microsoft 专用 以下公共语言运行时 (CLR) 托管实体中不支持 Lambda:**`ref class`**、**`ref struct`**、**`value class`** 或 **`value struct`**。 如果你使用 Microsoft 专用的修饰符(例如 [`__declspec`](https://learn.microsoft.com/zh-cn/cpp/cpp/declspec?view=msvc-170)),可以紧接在 `parameter-declaration-clause` 后将其插入 Lambda 表达式。 例如: C++ 复制 ```auto auto Sqr = [](int t) __declspec(code_seg("PagedMem")) -> int { return t*t; }; ``` 若要确定 Lambda 是否支持某个特定修饰符,请参阅 [Microsoft 专用修饰符](https://learn.microsoft.com/zh-cn/cpp/cpp/microsoft-specific-modifiers?view=msvc-170)一文中有关该修饰符的部分。 Visual Studio 支持 C++11 标准 Lambda 功能和无状态 Lambda。 无状态 Lambda 可转换为使用任意调用约定的函数指针。 ## 另请参阅 [C++ 语言参考](https://learn.microsoft.com/zh-cn/cpp/cpp/cpp-language-reference?view=msvc-170) [C++ 标准库中的函数对象](https://learn.microsoft.com/zh-cn/cpp/standard-library/function-objects-in-the-stl?view=msvc-170) [函数调用](https://learn.microsoft.com/zh-cn/cpp/cpp/function-call-cpp?view=msvc-170) [`for_each`](https://learn.microsoft.com/zh-cn/cpp/standard-library/algorithm-functions?view=msvc-170#for_each)
admin
2024年8月28日 13:21
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码