首页/新闻资讯/正文详情

C++ Lambda 表达式详解:从基本语法到捕获列表

发布时间:2026/9/26 11:12:32 来源:云帆数科 栏目:资讯中心
C++ Lambda 表达式详解:从基本语法到捕获列表
在学习 C 和 Qt 的过程中经常会看到这样的代码auto bitsum [](int x) - int { int res 0; while (x) { res x % 10; x / 10; } return res; };或者在 Qt 的connect()中看到connect(button, QPushButton::clicked, this, [sender]() { sender-sendData(); });刚开始看到[]、[sender]很容易疑惑。其实这两段代码使用的都是同一个 C 特性Lambda 表达式。本文从 Lambda 的基本语法开始重点介绍最容易混淆的捕获列表。一、什么是 Lambda 表达式Lambda 可以简单理解为在代码中直接定义一个匿名函数。例如普通函数int add(int a, int b) { return a b; }如果这个函数只使用一次其实没有必要专门给它起一个函数名。可以直接写成 Lambdaauto add [](int a, int b) - int { return a b; }; cout add(3, 5);输出8这里的add是一个变量它保存了这个 Lambda。因此可以通过add(3, 5);调用它。二、Lambda 的基本语法Lambda 的常见完整形式是[capture](parameters) - return_type { // 函数体 };例如auto add [](int a, int b) - int { return a b; };可以拆成[] (int a, int b) - int │ │ │ 捕获列表 参数列表 返回值类型最后{ return a b; }是 Lambda 的函数体。三、[]是什么Lambda 最前面的[]叫做捕获列表Capture List这是 Lambda 与普通函数一个非常重要的区别。捕获列表主要解决一个问题Lambda 如果需要使用外部作用域中的局部变量该怎么办例如void test() { int x 10; auto func []() { cout x; }; }这段代码会出错。因为x是test()中的局部变量而 Lambda 默认不能直接访问这个外部局部变量。可以通过捕获列表解决void test() { int x 10; auto func [x]() { cout x; }; }这里[x]表示把外面的x捕获到 Lambda 中。四、[x]按值捕获最基本的捕获方式是[x]表示按照值捕获x。例如int x 10; auto func [x]() { cout x; }; func();输出10可以把它简单理解成 Lambda 保存了一份x的副本。因此int x 10; auto func [x]() { cout x; }; x 20; func();输出仍然是10因为 Lambda 中保存的是捕获时的x副本。五、[x]按引用捕获如果写成[x]则表示按引用捕获x。例如int x 10; auto func [x]() { cout x; }; x 20; func();输出20因为 Lambda 访问的是外部原来的x。甚至可以直接修改它int x 10; auto func [x]() { x 100; }; func(); cout x;输出100所以可以简单记忆[x] → 按值捕获 [x] → 按引用捕获六、[]不捕获任何外部变量例如auto func []() { cout Hello; };这里[]表示不捕获任何外部局部变量。前面 LeetCode 中的数位和代码就是这种情况auto bitsum [](int x) - int { int res 0; while (x) { res x % 10; x / 10; } return res; };这里的x并不是外部变量。它来自(int x)也就是说x → Lambda 的参数而不是x → 外部变量所以根本不需要捕获。七、[]默认按值捕获如果外面有多个变量int a 10; int b 20; int c 30;可以写auto func []() { cout a endl; cout b endl; cout c endl; };[]表示Lambda 中使用到的外部局部变量默认按照值捕获。这样就不需要写[a, b, c]八、[]默认按引用捕获同理auto func []() { a; b; c; };表示Lambda 中使用到的外部局部变量默认按照引用捕获。因此[] → 默认按值捕获 [] → 默认按引用捕获这是非常常用的两种写法。九、捕获列表可以混合使用捕获列表并不只能全部按值或者全部按引用。例如int a 10; int b 20; auto func [a, b]() { cout a endl; b; };这里[a, b]表示a → 按值捕获 b → 按引用捕获也可以使用默认捕获方式再单独指定某个变量。例如[, b]表示默认按值捕获但是b按引用捕获。而[, a]表示默认按引用捕获但是a按值捕获。十、Lambda 中的“参数”和“捕获”不要混淆这是学习 Lambda 时非常容易混淆的地方。例如auto func [x](int y) - int { return x y; };这里有三个不同的部分[x] → 捕获列表 (int y) → 参数列表 - int → 返回值类型其中x是外部变量通过捕获列表进入 Lambda。而y是调用 Lambda 时传入的参数。例如int x 10; auto func [x](int y) - int { return x y; }; cout func(5);结果15所以捕获列表解决的是“Lambda 如何使用外部变量”参数列表解决的是“调用 Lambda 时如何传入参数”。十一、Lambda 在 Qtconnect()中的使用Lambda 在 Qt 中非常常见尤其是connect()。例如connect(button, QPushButton::clicked, this, []() { qDebug() 按钮被点击; });这里第四个参数就是一个 Lambda[]() { qDebug() 按钮被点击; }因为这个 Lambda 不需要使用外部局部变量所以捕获列表为空[]十二、Qt 中为什么会出现[sender]再看一个实际例子Sender *sender new Sender; connect(button, QPushButton::clicked, this, [sender]() { sender-sendData(); });这里Sender *sender new Sender;定义了一个局部变量sender而 Lambda 中需要使用这个变量sender-sendData();因此需要在捕获列表中写[sender]表示按值捕获外部的sender变量。这里尤其要注意Sender *sender中的sender是一个指针变量。所以[sender]捕获的是这个指针变量而不是Sender类型。可以简单理解为外部 sender ─────────→ Sender对象 │ │ 按值捕获 ↓ Lambda sender ─────────→ 同一个Sender对象指针本身复制了一份但是两个指针仍然指向同一个对象。十三、[sender]和[sender]的区别假设Sender *sender new Sender;那么[sender]表示按值捕获指针变量。而[sender]表示按引用捕获指针变量。也就是说两者的区别是[sender] ↓ 复制一份指针 [sender] ↓ 引用原来的指针变量在 Qt 的很多场景中如果只是需要 Lambda 使用这个指针常见写法就是[sender]十四、为什么 Lambda 在 Qt 中特别常见因为 Qt 的connect()可以直接接收 Lambda。例如connect(button, QPushButton::clicked, this, [this]() { ui-label-setText(Hello); });这里[this]也是一种捕获。它表示捕获当前对象的this指针。于是 Lambda 中可以使用ui-label等当前对象的成员。因此你在 Qt 项目中看到[this]()[sender]()[data]()本质上都是在使用 Lambda 的捕获列表。十五、Lambda 常见写法总结可以先记住下面这张表写法含义[]不捕获外部变量[x]按值捕获x[x]按引用捕获x[]外部变量默认按值捕获[]外部变量默认按引用捕获[a, b]a按值b按引用[, b]默认按值但b按引用[, a]默认按引用但a按值十六、回到最开始的 LeetCode 代码现在再看这段代码auto bitsum [](int x) - int { int res 0; while (x) { res x % 10; x / 10; } return res; };就很好理解了。auto bitsum ↓ 用一个变量保存 Lambda [] ↓ 不捕获外部变量 (int x) ↓ Lambda 的参数 - int ↓ 返回 int { ... } ↓ Lambda 函数体而 Qt 中[sender]() { sender-sendData(); }则是[sender] ↓ 按值捕获外部的 sender () ↓ 没有参数 { sender-sendData(); } ↓ 使用捕获进来的 sender因此理解 Lambda 最重要的就是先分清楚这三个部分[capture](parameters) - return_type其中捕获列表决定 Lambda 能不能使用外部变量以及如何捕获这些变量参数列表决定调用 Lambda 时接收什么参数返回值类型决定 Lambda 返回什么类型。掌握这几个基本概念后再看 C STL、Qtconnect()中的大量 Lambda 写法就不会再觉得[]、[this]、[sender]很神秘了。

相关推荐

【linux系统】两条命令搞定 openclaw 安装启动,TaoToken 配置一次到位
【linux系统】两条命令搞定 openclaw 安装启动,TaoToken 配置一次到位

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 11:12:26

ESP32上运行WASM的真相:不是CPU原生支持,而是轻量VM解释执行
ESP32上运行WASM的真相:不是CPU原生支持,而是轻量VM解释执行

1. 这不是“CPU运行WASM”,而是“在ESP32上跑WASM解释器”——先破一个广泛存在的认知误区你搜“ESP32 WASM”时,大概率会看到标题党文章写着“ESP32原生支持WebAssembly”“单片机也能跑WASM应用”,甚至配上一张ESP32开发板接LED闪烁的动图&… · 2026/9/26 11:12:26

让 AI 直接操作数据库:电科金仓 KES MCP Server 配置与验证实践
让 AI 直接操作数据库:电科金仓 KES MCP Server 配置与验证实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 11:12:26

2026国自然评审改革下,跨学科基金申请书如何打动多元评审专家?
2026国自然评审改革下,跨学科基金申请书如何打动多元评审专家?

每年国自然申报季,青年学者群里总少不了“本子写好了,方向太交叉怕被毙”“创新点很大,但评审专家背景太杂怎么讲”这类焦虑。2026年的评审改革,把这个矛盾又放大了整整一轮:分类评审更细、函评专家匹配更看重交叉学科… · 2026/9/26 12:26:31

睡岗检测实战:基于YOLOv8的VOC数据集训练与ONNX部署指南
睡岗检测实战:基于YOLOv8的VOC数据集训练与ONNX部署指南

简介:面向需要训练睡岗检测模型的算法工程师与研究人员,这套采用VOC标记格式的数据集覆盖了桌子上趴睡、埋头睡觉、座椅上靠睡、平躺等多种典型睡姿,适合用于安防监控、工厂园区等场景下的目标检测算法开发与评估。资源包整体大小约422.3MB&a… · 2026/9/26 12:26:31

Java泛型从类型擦除到实战:通配符、Feign与避坑指南
Java泛型从类型擦除到实战:通配符、Feign与避坑指南

如果你写Java已经有一两年,肯定被泛型坑过不少次。不管是写工具类、封装BaseDao,还是调用OpenFeign、Spring的RestTemplate,泛型都是绕不开的话题。我见过很多人面试时能背出“泛型是类型参数化”,但真到写代码时,连&l… · 2026/9/26 12:26:31

Windsurf 免积分使用 Claude 和 GPT5.2:settings.json 配置骨架与验证
Windsurf 免积分使用 Claude 和 GPT5.2:settings.json 配置骨架与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 12:26:31

C#上位机集成YOLOv8+OpenVINO+ByteTrack实现实时目标检测与跟踪
C#上位机集成YOLOv8+OpenVINO+ByteTrack实现实时目标检测与跟踪

简介:C#结合OpenVINO与ByteTrack的YOLOv8实时目标检测Demo,面向需要在C#环境中落地视觉检测与多目标追踪的开发者。资源以完整工程形式提供,涵盖YOLOv8模型转换、OpenVINO推理、视频流处理及ByteTrack轨迹关联等核心环节,解决模型… · 2026/9/26 12:26:31

3分钟搞懂BI核心逻辑:Power BI实操与AI大模型新玩法
3分钟搞懂BI核心逻辑:Power BI实操与AI大模型新玩法

很多人一听到BI这个词,脑子里立刻弹出“商业智能”“数据仓库”“仪表盘”这些高大上的词,然后就开始犯晕。其实BI没那么玄乎,它就是一门“把数据变成决策”的手艺活。今天我打算用一篇完全没废话的实操笔记,带你3分钟搞懂BI的核心… · 2026/9/26 12:26:21

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码