【C++11】lambda表达式
前言:
随着 C++11 的发布,C++ 标准引入了许多新特性,使语言更加现代化,开发者编写的代码也变得更加简洁和易于维护。Lambda 表达式是其中一个重要的特性,它提供了一种方便的方式来定义匿名函数,这在函数式编程范式中非常常见。Lambda 表达式允许我们在函数内部定义小型的无名函数,减少了不必要的函数定义和代码冗余,是现代 C++ 开发的重要工具。
本文将详细介绍 C++11 中 Lambda 表达式的语法、使用场景、捕获机制以及高级应用,帮助读者充分理解并应用这个特性。
一、Lambda 表达式的基础
Lambda 表达式的基本语法如下:
[capture] (parameters) -> return_type { body }
capture
(捕获列表):定义了哪些外部变量会被“捕获”并在lambda
表达式内部使用。它可以按值或按引用捕获。parameters
(参数列表):与普通函数的参数列表相似,定义了传递给lambda
的参数。return_type
(返回类型):指定返回类型,C++11 可以自动推导返回类型,因此该部分可以省略。body
(函数体):lambda 实际执行的代码块。
一个简单的 Lambda 表达式示例:
auto add = [](int a, int b) -> int { return a + b; };
std::cout << add(5, 3) << std::endl; // 输出 8
这里我们定义了一个接受两个 int
参数并返回它们之和的匿名函数。lambda
通过 []
定义了捕获列表,(int a, int b)
是参数列表,-> int
是返回类型,而函数体 { return a + b; }
执行了实际的操作。
二、捕获列表
捕获列表定义了 lambda 可以使用的外部变量。捕获方式分为两种:按值捕获和按引用捕获。通过不同的捕获方式,可以控制 lambda 对外部变量的访问和修改行为。
1. 不捕获任何变量
如果 lambda 不需要使用任何外部变量,可以使用空捕获列表:
auto sayHello = []() { std::cout << "Hello, World!" << std::endl; };
sayHello(); // 输出:Hello, World!
2. 按值捕获(=
)
按值捕获意味着 lambda 内部得到的是捕获变量的副本,因此在 lambda 内对该变量的修改不会影响外部变量。
int x = 10;
auto captureByValue = [x]() { std::cout << x << std::endl; };
x = 20;
captureByValue(); // 输出 10
在上面的例子中,虽然我们在 lambda 定义之后修改了 x
的值,但 lambda 捕获的是 x
的副本,因此输出的仍然是 10。
3. 按引用捕获(&
)
按引用捕获则允许 lambda 直接访问外部变量并修改它的值。
int x = 10;
auto captureByReference = [&x]() { x += 10; };
captureByReference();
std::cout << x << std::endl; // 输出 20
这里我们通过 &x
将 x
按引用捕获,因此在 lambda 中对 x
的修改会直接影响外部变量。
4. 捕获特定变量
可以只捕获特定的变量,而不是捕获所有外部变量。捕获方式可以是按值或按引用:
int a = 5, b = 10;
auto captureSpecific = [a, &b]() {std::cout << "a: " << a << std::endl;std::cout << "b: " << b << std::endl;b = 20;
};
captureSpecific();
std::cout << "b: " << b << std::endl; // 输出 20
在这个例子中,a
被按值捕获,b
被按引用捕获。lambda 内部修改了 b
,而外部的 b
也受到了影响。
5. 捕获所有变量([=]
和 [&]
)
[=]
:按值捕获所有外部变量。[&]
:按引用捕获所有外部变量。
int x = 5, y = 10;
auto captureAllByValue = [=]() {std::cout << "x: " << x << ", y: " << y << std::endl;
};
captureAllByValue(); // 输出:x: 5, y: 10auto captureAllByReference = [&]() {x += 10;y += 10;
};
captureAllByReference();
std::cout << "x: " << x << ", y: " << y << std::endl; // 输出:x: 15, y: 20
通过 [=]
,lambda 按值捕获了 x
和 y
,因此即使在外部修改了 x
和 y
,lambda 内的 x
和 y
仍然保持不变。而通过 [&]
,lambda 可以直接修改外部的 x
和 y
。
三、Lambda 表达式的返回类型
在 C++11 中,lambda 的返回类型可以自动推导,也可以显式指定。通常,如果 lambda 体中只有一个 return
语句,编译器会自动推导返回类型:
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << std::endl; // 输出 7
如果 lambda 体中有复杂的逻辑或多个 return
语句,建议使用 ->
明确指定返回类型:
auto complexLambda = [](int a, int b) -> int {if (a > b) return a;else return b;
};
std::cout << complexLambda(3, 4) << std::endl; // 输出 4
自动推导有时会导致问题,特别是当 lambda 返回一个引用或指针时,明确返回类型显得尤为重要。
四、Lambda 的常见使用场景
1. 用于标准算法
C++ 标准库中提供了许多算法,如 std::sort
、std::for_each
等,lambda 可以很方便地作为这些算法的回调函数使用。
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int &n) { n *= 2; });
for (auto n : v) std::cout << n << " "; // 输出 2 4 6 8 10
在这个例子中,lambda 作为 std::for_each
的参数,将每个元素乘以 2。
2. 用于排序
使用 lambda
作为自定义排序条件,可以让排序更加灵活。
std::vector<int> v = {5, 2, 9, 1, 5, 6};
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
for (auto n : v) std::cout << n << " "; // 输出 9 6 5 5 2 1
这里,我们通过 lambda 定义了一个降序排序的条件。
3. 用于事件回调
在 GUI 或网络编程中,lambda 常用于定义事件的回调函数。例如,在按钮点击事件中:
button.onClick([]() {std::cout << "Button clicked!" << std::endl;
});
lambda 作为回调函数的使用使得代码更加简洁。
五、Lambda 表达式的高级用法
1. 捕获 this
指针
在类成员函数中,lambda 可以通过 [this]
捕获当前对象的 this
指针,这样就可以访问类的成员变量和成员函数。
class MyClass {
public:int value = 42;void printValue() {auto lambda = [this]() {std::cout << "Value: " << value << std::endl;};lambda();}
};int main() {MyClass obj;obj.printValue(); // 输出:Value: 42
}
通过捕获 this
指针,lambda 可以访问和修改对象的成员。
2. 可变的 Lambda 表达式
默认情况下,lambda 是不可修改其捕获的值的。如果需要修改捕获的值,可以在捕获列表后加上 mutable
关键字:
intx = 10;
auto mutableLambda = [x]() mutable {x += 10;std::cout << "Inside lambda: " << x << std::endl;
};
mutableLambda();
std::cout << "Outside lambda: " << x << std::endl; // 输出:Outside lambda: 10
mutable
使得 x
可以在 lambda 内部被修改,但不会影响外部的 x
。
六、结语
C++11 的 Lambda 表达式为开发者提供了一种高效、简洁的方式来定义匿名函数,极大地增强了 C++ 的表达能力。理解并掌握 lambda 的使用方式,将有助于写出更现代、更易读的 C++ 代码 参考。
相关文章:
【C++11】lambda表达式
前言: 随着 C11 的发布,C 标准引入了许多新特性,使语言更加现代化,开发者编写的代码也变得更加简洁和易于维护。Lambda 表达式是其中一个重要的特性,它提供了一种方便的方式来定义匿名函数,这在函数式编程范…...

前端学习-css的背景(十六)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 背景颜色 语法格式 背景图片 语法格式 背景平铺 语法格式 背景图片位置 语法格式 参数代表的意思 参数是方位名词 参数是精确单位 参数是混合单位 背…...

使用Postman搞定各种接口token实战
现在许多项目都使用jwt来实现用户登录和数据权限,校验过用户的用户名和密码后,会向用户响应一段经过加密的token,在这段token中可能储存了数据权限等,在后期的访问中,需要携带这段token,后台解析这段token才…...

ssh连接慢的问题或远程连接服务超时
问题原因: 在SSH登录过程中,服务器会通过反向DNS查找客户端的主机名,然后与登录的IP地址进行匹配,以验证登录的合法性。如果客户端的IP没有域名或DNS服务器响应缓慢,这可能导致SSH登录过慢。为了解决这个问题…...

基于卷积神经网络的蔬菜识别系统,resnet50,mobilenet模型【pytorch框架+python源码】
更多目标检测和图像分类识别项目可看我主页其他文章 功能演示: 基于卷积神经网络的蔬菜识别系统,resnet50,mobilenet【pytorch框架,python,tkinter】_哔哩哔哩_bilibili (一)简介 基于卷积神…...

数据结构与算法:栈与队列的高级应用
目录 3.1 栈的高级用法 3.2 队列的深度应用 3.3 栈与队列的综合应用 总结 数据结构与算法:栈与队列的高级应用 栈和队列是两种重要的线性数据结构,它们在计算机科学和工程的许多领域都有广泛的应用。从函数调用到表达式求值,再到任务调度…...
macos php开发环境之macport安装的php扩展安装,php常用扩展安装,port中可用的所有php扩展列表
macos中,我们使用了port 安装了php后,默认只带有php基本的核心扩展的, 如果需要使用其他的扩展,如 redis, https, xdebug等扩展就需要我们手动来安装对应的扩展。 macos php开发环境 macport安装的php的方法见macos 中…...

使用Pytorch+Numpy+Matplotlib实现手写字体分类和图像显示
文章目录 1.引用2.内置图片数据集加载3.处理为batch类型4.设置运行设备5.查看数据6.绘图查看数据图片(1)不显示图片标签(2)打印图片标签(3)图片显示标签 7.定义卷积函数8.卷积实例化、损失函数、优化器9.训练和测试损失、正确率(1)训练(2)测试(3)循环(4)损失和正确率曲线(5)输出…...
kimi帮我解决ubuntu下软链接文件夹权限不够的问题
我的操作如下 ubuntuubuntu-QiTianM420-N000:~$ ln -s /media/ubuntu/4701aea3-f883-40a9-b12f-61e832117414 code ubuntuubuntu-QiTianM420-N000:~$ ls -l 总用量 636 drwxrwxr-x 2 ubuntu ubuntu 4096 5月 7 17:16 bin drwxrwxrwx 2 ubuntu ubuntu 4096 5月 8 13…...

如何去除背景音乐保留人声?保留人声,消除杂音
在日常生活和工作中,我们经常遇到需要处理音频的情况,尤其是当我们想要去除背景音乐,仅保留人声时。这种需求在处理电影片段、制作音乐MV、或者提取演讲内容等场景中尤为常见。本文将为您详细介绍如何去除背景音乐并保留人声,帮助…...
2.4.ReactOS系统提升IRQL级别KfRaiseIrql 函数
2.4.ReactOS系统提升IRQL级别KfRaiseIrql 函数 2.4.ReactOS系统提升IRQL级别KfRaiseIrql 函数 文章目录 2.4.ReactOS系统提升IRQL级别KfRaiseIrql 函数KfRaiseIrql 函数 KfRaiseIrql 函数 /*********************************************************************** NAME …...

【新书】使用 OpenAI API 构建 AI 应用:利用 ChatGPT等构建 10 个 AI 项目(第二版),404页pdf
通过构建 ChatGPT 克隆、代码错误修复器、测验生成器、翻译应用、自动回复邮件生成器、PowerPoint 生成器等项目,提升您的应用开发技能。 关键特性 通过掌握 ChatGPT 概念(包括微调和集成),转变为 AI 开发专家 通过涵盖广泛 AI …...
修改PostgreSQL表中的字段排列顺序
二、通过修改系统表(pg_attribute)达到字段重新排序的目的有关系统表的概述及用途可以查看官网:http://www.pgsqldb.org/pgsqldoc-cvs/catalogs.html 表名字表用途pg_class表,索引,序列,视图(”关系”)pg_…...

canvas实现手写功能
1.从接口获取手写内容,处理成由单个字组成的数组(包括符号) 2.合成所有图的时候,会闪现outputCanvas合成的图,注意隐藏 3.可以进行多个手写内容切换 4.基于uniapp的 <template><view class"content&quo…...
Python知识点:基于Python技术,如何使用TensorFlow进行目标检测
开篇,先说一个好消息,截止到2025年1月1日前,翻到文末找到我,赠送定制版的开题报告和任务书,先到先得!过期不候! 使用TensorFlow进行目标检测的完整指南 目标检测是计算机视觉领域中的一项重要任…...

初始爬虫13(js逆向)
为了解决网页端的动态加载,加密设置等,所以需要js逆向操作。 JavaScript逆向可以分为三大部分:寻找入口,调试分析和模拟执行。 1.chrome在爬虫中的作用 1.1preserve log的使用 默认情况下,页面发生跳转之后…...
前端发送了请求头的参数,经debug发现后端请求对象请求头中没有该参数
debug测试,发现前端发来请求头中确实没有找到添加的请求头参数,但是 Network 中却显示请求头中有该参数信息。 原因是RequestHeaders中设置的请求参数含有下划线,NGINX将静默地丢弃带有下划线的HTTP标头,这样做是为了防止在将头映…...

雷池社区版如何使用静态资源的方式建立站点
介绍: SafeLine,中文名 “雷池”,是一款简单好用, 效果突出的 Web 应用防火墙(WAF),可以保护 Web 服务不受黑客攻击。 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、X…...

车载电源OBC+DC/DC
文章目录 1. 车载DC/DC应用场景2. PFC2.1 简介2.2 专业名词2.3 常见拓扑结构2.3.1 传统桥式PFC2.3.2 普通无桥型PFC2.3.3 双Boost无桥PFC2.3.4 图腾柱PFC2.3.5 参考资料 2.4 功率因数2.4.1 简介2.4.2 计算 3. DC/DC3.1 Boost升压电路3.1.1 简介3.1.2 电路框图3.1.3 工作原理3.1…...

【朝花夕拾】免费个人网页搭建:免费托管、CDN加速、个人域名、现代化网页模板一网打尽
现代化网页设计的免费宝藏:GitHub PagesCodePenCloudflareUS.KG 前言 在当今数字化时代,个人和企业越来越重视在线形象的建立。GitHub Pages 提供了一个免费且便捷的平台,允许用户托管静态网站。然而,GitHub Pages 默认的域名可…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...