C++笔记之lambda表达式

引言
Lambda表达式是从C++ 11版本引入的特性,利用它可以很方便的定义匿名函数对象,通常作为回调函数来使用。大家会经常拿它和函数指针,函数符放在一起比较,很多场合下,它们三者都可以替换着用。
语法
[ captures ] ( params ) specs requires (optional) {body}
上面是完整的Lambda表达式结构,从左到右分别是:
- capture–捕获列表
- params–参数列表
- specification列表-- 可选部分,这块部分主要由变量说明符、异常、返回类型等组成
- requires – C++20 版本开始增加的
- body-- 函数体
关于specification和requires部分的详细描述可以参考:https://en.cppreference.com/w/cpp/language/lambda
我们平时的开发工作可能不会基于C++20版本,一般都是C++17及以下,所以就先记录一下,平时开发所接触的Lambda表达式。哪些新版本增加的相关特性就暂不讨论。
常见的Lambda表达式语法:

图片引自 微软C++课程
结构描述:
- 捕获列表,可以捕获外部变量
- 形参列表 (可选)
- 变量说明符(可选)属于specification列表,用来表示可以修改值捕获的变量,后面会详细说明
- exception (可选)属于specification列表,用来表示是否会有异常
- 返回类型 (可选)
- 函数体
从上面的结构描述,我们能看到,最简洁的lambda表达式应该是这样:
[]{}
我们常用的lambda表达式有以下几种:
[capture list]{body}
[capture list](params){body}
[capture list](params)->return type {body}
捕获列表
lambda表达式有两种捕获其作用域外部变量的方式,一种是值捕获,一种是引用捕获。
值捕获
#include <iostream>
using namespace std;
int main(int argc, char **argv) {int a = 100;auto test = [a]() mutable {a++;cout << "inside, a:" << a << endl;};test();cout << "outsize, a:" << a << endl;return 0;
}
输出结果:
inside, a:101
outsize, a:100
值捕获的情况下,如果需要某个特地的外部变量,那么直接在捕获列表里面写相应的变量名即可,如果想要值捕获所以外部变量,可使用如下形式:
[=]
上面的例子中有mutable,这个关键字的作用是运行lambda内部可以修改值捕获的变量,默认情况下,值捕获的变量是只读的。
引用捕获
#include <iostream>
using namespace std;
int main(int argc, char **argv) {int a = 100;auto test = [&a]() {a++;cout << "inside, a:" << a << endl;};test();cout << "outsize, a:" << a << endl;return 0;
}
输出结果:
inside, a:101
outsize, a:101
引用捕获外部变量的话,需要在变量名前加上**&,如果想要以引用捕获的方式访问所以外部变量,可以使用:[&]**
注意,这里我们移除了mutable关键字。
值捕获&引用捕获
因为是捕获列表嘛,所以当然可以互相组合搭配了,不然怎么能达到列表的定义呢。例如,我们想要以值捕获的方式捕获factor变量,以引用捕获的方式捕获total变量,那么可以用如下的方式:
[&total, factor]
[factor, &total]
[&, factor]
[=, &total]
以上面第一个方式举个例子:
#include <iostream>
using namespace std;
int main(int argc, char **argv) {int total = 100;float factor = 0.2f;auto test = [&total, factor]() mutable {factor = 0.5f;total = static_cast<int>(total * factor);cout << "inside, total:" << total << ", factor:" << factor << endl;};test();cout << "outsize, total:" << total << ",factor:" << factor << endl;return 0;
}
输出结果:
inside, total:50, factor:0.5
outsize, total:50,factor:0.2
在两种捕获方式互相搭配的使用过程中,需要注意一点的是,当捕获列表中已经使用了**&来捕获所以外部变量,就不能再使用&变量名**,捕获指定变量了,同理,值捕获也是这样。例如:
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
}
注意
上面的例子中,访问外部的变量,都必须通过捕获列表“处理”一下,内部才能访问,其实还有一些情况是不需要捕获,lambda就能访问的。例如:
- 当lambda要访问的变量是全局的或者静态(static)的,可以直接使用
- Thread Local 变量
- constant expression 并且没有mutable成员 (只读)
- const修饰的non-volatile int型字面量 或者 由constant expression初始化的枚举类型 (只读)
下面举一些例子:
#include <iostream>
using namespace std;
int total = 100;
int main(int argc, char **argv) {static float factor = 0.2f;auto test = []() {factor = 0.5f;total = static_cast<int>(total * factor);cout << "inside,global total:" << total << ", static factor:" << factor<< endl;};test();cout << "outsize,global total:" << total << ", static factor:" << factor<< endl;return 0;
}
输出结果:
inside,global total:50, static factor:0.5
outsize,global total:50, static factor:0.5
#include <iostream>
#include <thread>
using namespace std;
int main(int argc, char **argv) {const int x = 1024;enum TYPE { kTypeApp = 0, kTypeUser };auto test = []() {cout << "type:" << kTypeUser << endl;cout << "x:" << x << endl;};test();return 0;
}
输出结果:
type:1
x:1024
参数列表&返回类型
lambda除了通过捕获列表的方式访问外部变量,也可以通过传递参数来与外界交流。跟普通函数没啥区别,这个没啥好说的。需要知道的是lambda支持它的参数也可以是lambda表示式。
返回类型跟普通函数差别也不大,同样需要注意的是,跟参数列表一样,也是支持返回lambda表达式的。同时,如果不指定返回类型的话,那么可以用auto关键字接收返回结果,自动推导结果。
#include <functional>
#include <iostream>
using namespace std;
int main() {auto addtwointegers = [](int x) -> function<int(int)> {return [=](int y) { return x + y; };};auto higherorder = [](const function<int(int)>& f, int z) {return f(z) * 2;};auto answer = higherorder(addtwointegers(7), 8);cout << answer << endl;
}
输出结果:
30
lambda嵌套
lambda表达式内部还可以创建lambda表达式,套娃的感觉🪆。
#include <iostream>
using namespace std;
int main()
{int ret = [](int x) { return [](int y) { return y * 2; }(x) + 3; }(5);cout << ret << endl;
}
输出结果:
13
参考
https://learn.microsoft.com/en-us/cpp/cpp/examples-of-lambda-expressions?view=msvc-170
https://en.cppreference.com/w/cpp/language/lambda
相关文章:
C++笔记之lambda表达式
引言 Lambda表达式是从C 11版本引入的特性,利用它可以很方便的定义匿名函数对象,通常作为回调函数来使用。大家会经常拿它和函数指针,函数符放在一起比较,很多场合下,它们三者都可以替换着用。 语法 [ captures ] (…...
flink大数据处理流式计算详解
flink大数据处理 文章目录flink大数据处理二、WebUI可视化界面(测试用)三、Flink部署3.1 JobManager3.2 TaskManager3.3 并行度的调整配置3.4 区分 TaskSolt和parallelism并行度配置四、Source Operator(资源算子)五、Sink Operator(输出算子)六、Flink滑…...
Java面试题(二十三)DCL单例
懒汉式单例 private static SingletonInstance INSTANCE;private SingletonInstance(){}public static SingletonInstance getInstance() {if (INSTANCE null) {INSTANCE new SingletonInstance();}return INSTANCE;}构造方法私有化,然后判断是否为空,…...
UML-类图
一、类 一个类由三个格子组成,从上至下分别表示: 第一格:类名称(接口和抽象类,使用斜体) 第二格:类的属性(成员变量,可以没有) 第三格:类的操作&…...
PostgreSQL 数据库和 pgAdmin 4
PostgreSQL 数据库和 pgAdmin 4PostgreSQLPostgreSQL 数据库安装PostgreSQL 数据库安装 (Ubuntu)PostgreSQL 数据库其他系统安装PostgreSQL 数据库快速使用入门登录数据库访问数据库参考pgAdmin 4pgAdmin 4 安装使用 pgAdmin 4 登录数据库参考PostgreSQL PostgreSQL 数据库安装…...
quarkus 搭建与基础开发环境配置总结
quarkus搭建与基础开发环境配置总结 大纲 基础概念quarkus2.13.7脚手架工程配置配置maven3.8.7quarkus快速启动quarkus的三种打包方式quarkus将程序打包为二进制文件window环境下quarkus云原生二进制文件打包环境搭建使用GraalVM-java11替换本地java8运行二进制文件 基础概念…...
扩散模型DDPM开源代码的剖析【对应公式与作者给的开源项目,diffusion model】
扩散模型DDPM开源代码的剖析【对应公式与作者给的开源项目,diffusion model】一、简介二、扩散过程:输入是x_0和时刻num_steps,输出是x_t三、逆扩散过程:输入x_t,不断采样最终输出x_0四、具体参考算法流程图五、模型mo…...
C语言 学生记录管理系统
学生记录管理系统 1--添加 2--删除 3--查询:按姓名 4--查询:按班级 5--查询:按学号 0--退出 请选择操作序号(0—5):1 请输入新学生的学号:1 请输入新学生的…...
【独家】华为OD机试 C 语言解题 - 交换字符
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...
网络安全平台测试赛 easyphp(phar脏数据处理)
昨天的比赛,14.00-17.00.时间有点紧张,比赛期间没拿下来这道 😭非常痛苦,很顺畅的思路 一步步想下来,卡在最后一步末尾脏数据处理了,最后时间到了 没打通,还需多练 这里本地复现一下࿱…...
【python】XML格式文件读写详解
注:最后有面试挑战,看看自己掌握了吗 文章目录XML介绍格式XML与AJAX与HTML区别联系生成XML文件案例用SAX模块处理XML用DOM模块处理XML🌸I could be bounded in a nutshell and count myself a king of infinite space. 特别鸣谢:…...
理解js的精度问题
参考博客:js精度丢失问题-看这篇文章就够了(通俗易懂)、探寻 JavaScript 精度问题以及解决方案、JavaScript 浮点数陷阱及解法 1 为什么 JavaScript 中所有数字包括整数和小数都只有一种类型 即 Number类型,它的实现遵循 IEEE 754 标准。 符号位S&#…...
蓝桥杯 时间显示
题目 输入输出样例 示例 1 输入 46800999输出 13:00:00示例 2 输入 1618708103123输出 01:08:23评测用例规模与约定 对于所有评测用例,给定的时间为不超过 10^{18}1018 的正整数。 运行限制 最大运行时间:1s最大运行内存: 512M 基础知识 时间的转换…...
qt中设置菜单高度
如题所示,我建立一个菜单,代码如下,但是菜单项的高度太小了, { popupMenu new QMenu(this); QAction *action1 new QAction(tr(“&New1”), this); QAction *action2 new QAction(tr(“&New2”), this); QA…...
测开:前端基础-css页面布局-定位
一 、传统网页布局的三种方式 网页布局的本质–用CSS来摆放盒子,把盒子摆放到相应的位置,css提供了三种传统布局方式,分别是标准流,浮动和定位三种。 二、 定位 2.1 啥是定位 我的理解,就是要把这个元素,…...
Servlet中八个监听器介绍
一、监听对象创建的监听器 1、ServletContextListener /*** 用于监听ServletContext对象创建和销毁的监听器* since v 2.3*/public interface ServletContextListener extends EventListener {/*** 对象创建时执行此方法。该方法的参数是ServletContextEvent事件对象…...
LicenseBox Crack,对服务器的要求最低
LicenseBox Crack,对服务器的要求最低 LicenseBox是用于管理基于PHP的软件、WordPress插件或主题、主题、插件和WordPress的更新和许可的完整软件。它易于安装,对服务器的要求最低,用户友好的界面,无限脚本的使用为您的创造力打开了大门。 Li…...
css中重难点整理(vertical-align)
一、vertical-align 在学习vertical-align的时候,可能会很困惑。即使网上有一大推文章讲veitical-align,感觉看完好像懂了,等自己布局的时候用到vertical-align的时候好像对它又很陌生。这就是我在布局的时候遇到的问题。 本来vertical-align就很不好理…...
javaScript基础面试题 ---宏任务微任务
宏任务微任务一、为什么JS是单线程语言?二、JS是单线程,怎样执行异步代码?1、JS是单线程语言 2、JS代码执行流程,同步执行完,再进行事件循环(微任务、宏任务) 3、清空所有的微任务,再…...
基于JSP的网上书城
技术:Java、JSP等摘要:随着科技的迅速发展,计算机技术已应用到社会的各个领域。随着计算机技术和通信技术的迅速发展,网络的规模也逐渐增大,网络的元素也随之不断增加,有的利用其通信,有的利用其…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
C++ 类基础:封装、继承、多态与多线程模板实现
前言 C 是一门强大的面向对象编程语言,而类(Class)作为其核心特性之一,是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性,包括封装、继承和多态,同时讨论类中的权限控制,并展示如何使用类…...
中科院1区顶刊|IF14+:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点
中科院1区顶刊|IF14:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点 当下,免疫与代谢性疾病的关联研究已成为生命科学领域的前沿热点。随着研究的深入,我们愈发清晰地认识到免疫系统与代谢系统之间存在着极为复…...
Electron简介(附电子书学习资料)
一、什么是Electron? Electron 是一个由 GitHub 开发的 开源框架,允许开发者使用 Web技术(HTML、CSS、JavaScript) 构建跨平台的桌面应用程序(Windows、macOS、Linux)。它将 Chromium浏览器内核 和 Node.j…...
解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法
目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客:【写在创作纪念日】基于SpringBoot和PostG…...
Clickhouse统计指定表中各字段的空值、空字符串或零值比例
下面是一段Clickhouse SQL代码,用于统计指定数据库中多张表的字段空值情况。代码通过动态生成查询语句实现自动化统计,处理逻辑如下: 从系统表获取指定数据库(替换your_database)中所有表的字段元数据根据字段类型动态…...
