C++ λ表达式

λ表达式提供了函数对象的另一种编程机制。


在 C++ 11 和更高版本中,Lambda 表达式(通常称为 Lambda)是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象(闭包)的简便方法。 Lambda 通常用于封装传递给算法或异步函数的少量代码行。

λ表达式

#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);
}

  1. capture 子句(在 C++ 规范中也称为 Lambda 引导。)

  2. 参数列表(可选)。 (也称为 Lambda 声明符)

  3. mutable 规范(可选)。

  4. exception-specification(可选)。

  5. trailing-return-type(可选)。

  6. Lambda 体。

capture子句

Lambda 可在其主体中引入新的变量(用 C++14),它还可以访问(或“捕获”)周边范围内的变量。 Lambda 以 capture 子句开头。 它指定捕获哪些变量,以及捕获是通过值还是通过引用进行的。 有与号 (&) 前缀的变量通过引用进行访问,没有该前缀的变量通过值进行访问。

空 capture 子句 [ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。

可以使用默认捕获模式来指示如何捕获 Lambda 体中引用的任何外部变量:[&] 表示通过引用捕获引用的所有变量,而 [=] 表示通过值捕获它们。 可以使用默认捕获模式,然后为特定变量显式指定相反的模式。

 例如,如果 lambda 体通过引用访问外部变量 total 并通过值访问外部变量 factor,则以下 capture 子句等效:

[&total, factor]
[factor, &total]
[&, factor]
[=, &total]

如果 capture 子句包含默认捕获 &,则该 capture 子句的捕获中没有任何标识符可采用 &identifier 形式。 同样,如果 capture 子句包含默认捕获 =,则该 capture 子句没有任何捕获可采用 =identifier 形式。 标识符或 this 在 capture 子句中出现的次数不能超过一次。 以下代码片段给出了一些示例:

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
}

捕获后跟省略号是一个包扩展,如以下可变参数模板示例中所示:

template<class... Args>
void f(Args... args) {auto x = [args...] { return g(args...); };x();
}

 要在类成员函数体中使用 Lambda 表达式,请将 this 指针传递给 capture 子句,以提供对封闭类的成员函数和数据成员的访问权限。

在使用 capture 子句时,建议你记住以下几点(尤其是使用采取多线程的 Lambda 时):

  • 引用捕获可用于修改外部变量,而值捕获却不能实现此操作。 (mutable 允许修改副本,而不能修改原始项。)

  • 引用捕获会反映外部变量的更新,而值捕获不会。

  • 引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。 当 Lambda 以异步方式运行时,这一点尤其重要。 如果在异步 Lambda 中通过引用捕获局部变量,该局部变量将很容易在 Lambda 运行时消失。 代码可能会导致在运行时发生访问冲突。

捕获特定的变量

在 C++14 中,可在 Capture 子句中引入并初始化新的变量,而无需使这些变量存在于 Lambda 函数的封闭范围内。 初始化可以任何任意表达式表示;且将从该表达式生成的类型推导新变量的类型。 借助此功能,你可以从周边范围捕获只移动的变量(例如 std::unique_ptr)并在 Lambda 中使用它们。

pNums = make_unique<vector<int>>(nums);
//...auto a = [ptr = move(pNums)](){// use ptr};

参数列表

Lambda 既可以捕获变量,也可以接受输入参数。 参数列表(在标准语法中称为 Lambda 声明符)是可选的,它在大多数方面类似于函数的参数列表。

auto y = [] (int first, int second)
{return first + second;
};

在 C++14 中,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。 此关键字将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 auto 实例等效于一个不同的类型参数。

在 C++14 中,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。 此关键字将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 auto 实例等效于一个不同的类型参数。

 Lambda 表达式可以将另一个 Lambda 表达式作为其自变量。 有关详细信息,请参阅 Lambda 表达式示例一文中的“高阶 Lambda 表达式”。

由于参数列表是可选的,因此在不将自变量传递到 Lambda 表达式,并且其 Lambda 声明符不包含 exception-specification、trailing-return-type 或 mutable 的情况下,可以省略空括号。

mutable 规范

通常,Lambda 的函数调用运算符是 const-by-value,但对 mutable 关键字的使用可将其取消。它不产生 mutable 数据成员。 利用 mutable 规范,Lambda 表达式的主体可以修改通过值捕获的变量。 本文后面的一些示例将展示如何使用 mutable

异常规范

// throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{[]() noexcept { throw 5; }();
}

 有关详细信息,请参阅异常规范 (throw)。

返回类型

将自动推导 Lambda 表达式的返回类型。 无需使用 auto 关键字,除非指定了 trailing-return-type。 trailing-return-type 类似于普通函数或成员函数的 return-type 部分。 但是,返回类型必须跟在参数列表的后面,你必须在返回类型前面包含 trailing-return-type 关键字 ->

如果 Lambda 体仅包含一个返回语句,则可以省略 Lambda 表达式的 return-type 部分。 或者,在表达式未返回值的情况下。 如果 lambda 体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。 否则,编译器会将返回类型推导为 void。 下面的示例代码片段说明了这一原则:

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 表达式示例中的“高阶 Lambda 表达式”。

Lambda 体

Lambda 表达式的 Lambda 体是一个复合语句。 它可以包含普通函数或成员函数体中允许的任何内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型:

  • 从封闭范围捕获变量,如前所述。

  • 参数。

  • 本地声明变量。

  • 类数据成员(在类内部声明并且捕获 this 时)。

  • 具有静态存储持续时间的任何变量(例如,全局变量)。

以下示例包含通过值显式捕获变量 n 并通过引用隐式捕获变量 m 的 lambda 表达式:

// 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;
}output
5
0

 由于变量 n 是通过值捕获的,因此在调用 lambda 表达式后,变量的值仍保持 0 不变。 mutable 规范允许在 Lambda 中修改 n

Lambda 表达式只能捕获具有自动存储持续时间的变量。 但是,可以在 Lambda 表达式体中使用具有静态持续存储时间的变量。 以下示例使用 generate 函数和 lambda 表达式为 vector 对象中的每个元素赋值。 lambda 表达式将修改静态变量以生成下一个元素的值。

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
}

模板和λ表达式

命名λ表达式

下面的代码示例使用上一示例中的函数,并添加了使用 C++ 标准库算法 generate_n 的 Lambda 表达式的示例。 该 lambda 表达式将 vector 对象的元素指派给前两个元素之和。 使用了 mutable 关键字,使 Lambda 表达式主体可以修改 Lambda 表达式通过值捕获的外部变量 x 和 y 的副本。 由于 lambda 表达式通过值捕获原始变量 x 和 y,因此它们的值在 lambda 执行后仍为 1

// 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 numbersfillVector(v);print("vector v after 1st call to fillVector(): ", v);// Fill the vector with the next sequence of numbersfillVector(v);print("vector v after 2nd call to fillVector(): ", v);
}output
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

constexpr Lambda 表达式

Visual Studio 2017 版本 15.3 及更高版本(在 /std:c++17 模式和更高版本中可用):在常量表达式中允许初始化捕获或引入的每个数据成员时,可以将 Lambda 表达式声明为 constexpr(或在常量表达式中使用它)。

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

auto answer = [](int n){return 32 + n;};constexpr int response = answer(10);

 如果 Lambda 是隐式或显式的 constexpr,则转换为函数指针将生成 constexpr 函数:

auto Increment = [](int n){return n + 1;};constexpr int(*inc)(int) = Increment;

Microsoft 专用

以下公共语言运行时 (CLR) 托管实体中不支持 Lambda:ref classref structvalue class 或 value struct

如果你使用 Microsoft 专用的修饰符(例如 __declspec),可以紧接在 parameter-declaration-clause 后将其插入 Lambda 表达式。 例如:

auto Sqr = [](int t) __declspec(code_seg("PagedMem")) -> int { return t*t; };

若要确定 Lambda 是否支持某个特定修饰符,请参阅 Microsoft 专用修饰符一文中有关该修饰符的部分。

Visual Studio 支持 C++11 标准 Lambda 功能和无状态 Lambda。 无状态 Lambda 可转换为使用任意调用约定的函数指针。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/625511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文笔记(三十九)Learning Human-to-Robot Handovers from Point Clouds

Learning Human-to-Robot Handovers from Point Clouds 文章概括摘要1. 介绍2. 相关工作3. 背景3.1. 强化学习3.2. 移交模拟基准 4. 方法4.1. Handover Environment4.2. 感知4.3. 基于视觉的控制4.4. 师生两阶段培训 (Two-Stage Teacher-Student Training) 5. 实验5.1. 模拟评估…

CSS实现平行四边形

1、为什么实现平行四边形 在日常开发过程中&#xff0c;有些时候我们可以会遇到一种情况&#xff0c;如可视化大屏中要求我们横线实现对应的进度条&#xff0c;但进度条的内容是由无数个平行四边形组装类似于进度条的形式&#xff0c;那么我们就需要使用CSS来进行对应的实现。 …

OPT(erlang)打造一套缓存系统(一)

缓存的设计 这个简易缓存存储的是键/值对&#xff0c;其中键与键之间不得重复&#xff0c;并且每个键只能映射到一个值。这个设计背后的核心思想是为写人缓存的每一个值都分配一个独立的存储进程再将对应的键映射至该进程。你可能会对这种为每个值分配一个进程的设计感到惊讶&…

20240114-寻找零损失或一损失的玩家

题目要求 给定一个整数数组 matches&#xff0c;其中 matches[i] [winneri, Loseri] 表示玩家 Winneri 在一场比赛中击败了玩家 Loseri。 返回大小为 2 的列表答案&#xff0c;其中&#xff1a; answer[0] 是所有未输掉任何比赛的玩家的列表。answer[1] 是仅输掉一场比赛的…

京东年度数据报告-2023全年度笔记本十大热门品牌销量(销额)榜单

2023年度&#xff0c;在电脑办公市场整体销售下滑的环境下&#xff0c;笔记本市场的整体销售也不景气。 根据鲸参谋平台的数据显示&#xff0c;京东平台上笔记本的年度销量为650万&#xff0c;同比下滑约16%&#xff1b;销售额约为330亿&#xff0c;同比下滑约19%。同时&#…

71.网游逆向分析与插件开发-角色数据的获取-修复角色名与等级显示问题

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;自动化助手UI显示角色数据-CSDN博客 码云地址&#xff08;ui显示角色数据 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;0049452c079867779…

微软Office 2021 批量许可版

软件介绍 微软办公软件套件Microsoft Office LTSC 2021 专业增强版2024年1月批量许可版更新推送&#xff01;Office2021正式版和Windows11系统同时于2021年10月份正式推出&#xff0c;Office LTSC 2021相比 Office2019正式版变化不太&#xff0c;最主要强化了LOGO设计趋势&…

电商物流查询:未来的发展方向

在电商日益繁荣的时代&#xff0c;物流信息查询不仅关乎消费者体验&#xff0c;更影响着电商运营的效率。快速、准确地追踪物流信息至关重要。本文将简述物流信息快速追踪的价值&#xff0c;并重点介绍固乔快递查询助手这一高效查询工具及其批量查询功能。 一、物流信息快速追踪…

arcgis javascript api4.x加载天地图wgs84(wkid:4326)坐标系

需求&#xff1a; 使用arcgis javascript api4.x以basetilelayer方式加载天地图wgs84&#xff08;wkid&#xff1a;4326&#xff09;坐标系 效果&#xff1a; 代码&#xff1a; 提示&#xff1a;&#xff08;下述三个文件放同一个文件夹下&#xff09; 4326.js define([ex…

python毕设选题 - 基于时间序列的股票预测于分析

文章目录 1 简介2 时间序列的由来2.1 四种模型的名称&#xff1a; 3 数据预览4 理论公式4.1 协方差4.2 相关系数4.3 scikit-learn计算相关性 5 金融数据的时序分析5.1 数据概况5.2 序列变化情况计算 最后 1 简介 Hi&#xff0c;大家好&#xff0c;今天向大家介绍一个大数据项目…

QTday6作业

思维导图: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QSqlDatabase>//数据库管理类 #include <QSqlQuery>//执行sql语句类 #include <QSqlRecord>//数据库记录类 #include <QSqlError>//数据库错误类 #include …

使用ChatGPT对进行论文改写与润色

一、内容改写 关键在于明确改写的具体要求。 例如:[论文内容] 可以指明需要提升该段落的流畅性和逻辑连贯性。 常用指令 细微调整文本 轻微编辑 重写以增强表述清晰度 简化句式 校正语法和拼写错误 提升文本的流畅性和条理性 优化词汇使用 调整文本风格 进行深度编辑…

leetcode 17 电话号码字母组合

题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “23” 输出&#xf…

2024年烟花爆竹储存证考试题库及烟花爆竹储存试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年烟花爆竹储存证考试题库及烟花爆竹储存试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机…

实践学习PaddleScience飞桨科学工具包

实践学习PaddleScience飞桨科学工具包 动手实践&#xff0c;在实践中学习&#xff01;本项目可以在AIStudio平台一键运行&#xff01;地址&#xff1a;https://aistudio.baidu.com/projectdetail/4278591 本项目第一次执行会报错&#xff0c;再执行一次即可。若碰到莫名其妙的…

数据可视化大屏自适应,保持比例不变形,满足不同分辨率的需求——利用transform的scale属性缩放,缩放整个页面。

文章目录 一、需求背景&#xff1a;二、需求分析&#xff1a;三、选择方案&#xff1a;四、实现代码&#xff1a;五、效果预览&#xff1a;六、封装组件&#xff1a; 一、需求背景&#xff1a; 数据可视化大屏是一种将数据、信息和可视化效果集中展示在一块或多块大屏幕上的技…

2020年财政收支

偶感兴趣&#xff0c;花了点时间整理 有兴趣的可以参照下面的链接整理完整2022年的数据&#xff0c;2023年的数据还有12月份的数据未出&#xff0c;估计在这几天出。 附 2022年的财政收支情况 2022年基金支出预算表 2020年的社保收入是7.6万亿。 上图个税金额写错了&#xff0c…

Mindspore 公开课 - CodeGeeX

CodeGeeX: 多语言代码生成模型 CodeGeeX 是一个具有130亿参数的多编程语言代码生成预训练模型。CodeGeeX采用华为MindSpore框架实现&#xff0c;在鹏城实验室“鹏城云脑II”中的192个节点&#xff08;共1536个国产昇腾910 AI处理器&#xff09;上训练而成。截至2022年6月22日&…

数据库结构文档生成方法二(EZDML)

EZDML 下载链接&#xff1a;EZDML - 下载 我们常用的是数据建模有PowerDesigner,EZDML也是一款数据建模工具&#xff0c;而且功能很多&#xff0c;除了生成sql&#xff0c;还可以生成前端后端代码等等。 我们直接下载最新版后点击安装&#xff0c;打开后会默认打开示例&#…

基于springboot数码论坛系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把数码论坛与现在网络相结合&#xff0c;利用java技术建设数码论坛系统&#xff0c;实现数码论坛的信息化。则对于进一步提高数码论坛发展&#xff0c;丰富数码论坛经验能起到不少的促进作用。 数码论坛系统能够通过互联网得到广泛…