【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 默认的域名可…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
