[C++11] Lambda 表达式

lambda 表达式(Lambda Expressions)作为一种匿名函数,为开发者提供了简洁、灵活的函数定义方式。相比传统的函数指针和仿函数,lambda 表达式在简化代码结构、提升代码可读性和编程效率方面表现出色。


Lambda 表达式的基本语法

在 C++ 中,lambda 表达式的格式如下:

[capture-list] (parameters) -> return type {function body
}

各部分含义:

  • **[capture-list]**:捕捉列表,指定lambda表达式可以访问的外部变量。捕捉列表,该列表总是出现在 <font style="color:rgb(31,35,41);">lambda</font> 函数的开始位置,编译器根据[]来判断接下来的代码是否为 <font style="color:rgb(31,35,41);">lambda</font> 函数,捕捉列表能够捕捉上下⽂中的变量供 <font style="color:rgb(31,35,41);">lambda</font> 函数使⽤,捕捉列表可以传值传引⽤捕捉,捕捉列表为空也不能省略
  • **(parameters)**:参数列表,类似普通函数的参数,如果不需要参数传递,则可以连同<font style="color:rgb(31,35,41);">( )</font>⼀起省略。
  • **-> return type**:返回值类型。通常可以省略,由编译器推导。
  • **function body**:函数体,实现具体的功能。
// 1、捕捉为空也不能省略
// 2、参数为空可以省略
// 3、返回值可以省略,可以通过返回对象⾃动推导
// 4、函数题不能省略
auto func1 = []
{cout << "hello bit" << endl;return 0;
};

示例代码

以下是一个简单的 lambda 表达式示例:

auto add = [](int x, int y) -> int {return x + y;
};
std::cout << add(3, 5) << std::endl; // 输出:8

捕捉列表的使用

捕捉列表的分类

捕捉列表可以在 lambda 表达式中允许访问外部作用域的变量。捕捉方式主要包括:

  1. 显式捕捉:在捕捉列表中显⽰的传值捕捉和传引⽤捕捉,捕捉的多个变量⽤逗号分割,例如在捕捉列表中使用传值[x, y]或传引用[&z]捕捉变量。
  2. 隐式捕捉:使用 =(按值捕捉)或 &(按引用捕捉)进行隐式捕捉,这样我们 lambda 表达式中⽤了哪些变量,编译器就会⾃动捕捉那些变量,底层汇编也是这样的。
  3. 混合捕捉:可混合显式与隐式捕捉,<font style="color:rgb(31,35,41);">[=, &x]</font>表⽰其他变量隐式值捕捉,x引⽤捕捉;<font style="color:rgb(31,35,41);">[&, x, y]</font>表⽰其他变量引⽤捕捉,x和y值捕捉。当使⽤混合捕捉时,第⼀个元素必须是&或=,并且&混合捕捉时,后⾯的捕捉变量必须是值捕捉,同理=混合捕捉时,后⾯的捕捉变量必须是引⽤捕捉。

使用时的注意事项

  1. 全局位置的<font style="color:rgb(31,35,41);">lambda</font>

lambda 表达式如果在函数局部域中,他可以捕捉 lambda 位置之前定义的变量。但是不能捕捉静态局部变量和全局变量,静态局部变量和全局变量也不需要捕捉,lambda 表达式中可以直接使⽤。这也意味着 lambda 表达式如果定义在全局位置,捕捉列表不需要捕捉任何变量,必须为空

// 全局
auto f1 = [](int a, int b){return a + b;
}
  1. mutable修饰lambda

默认情况下, lambda 捕捉列表是被const修饰的,也就是说传值捕捉的过来的对象不能修改,mutable加在参数列表的后⾯可以取消其常量性,也就说使⽤该修饰符后,传值捕捉的对象就可以修改了,但是修改还是形参对象,不会影响实参。使⽤该修饰符后,参数列表不可省略(即使参数为空)。

int a = 5, b = 10;
auto func = [=]() mutable {a++;         // 可以修改按引用捕捉的变量b++;
};

注意:默认情况下捕捉的变量为 const,无法在 lambda 中修改,除非在参数列表后加 mutable 修饰符,如上例中的 mutable

捕捉的具体示例

  1. 显式捕捉:
int a = 0, b = 1, c = 2, d = 3;
auto func1 = [a, &b]{// 值捕捉的变量不能修改,引⽤捕捉的变量可以修改//a++;b++;int ret = a + b;return ret;};
cout << func1() << endl;
  1. 隐式值捕捉 / 隐式引用捕捉:
// 隐式值捕捉
// ⽤了哪些变量就捕捉哪些变量
auto func2 = [=] {int ret = a + b + c;return ret;};
cout << func2() << endl;// 隐式引用捕捉
// ⽤了哪些变量就捕捉哪些变量
auto func3 = [&] {a++;c++;d++;};
func3();
cout << a << " " << b << " " << c << " " << d << endl;
  1. 混合捕捉:
// 混合捕捉1
auto func4 = [&, a, b] {//a++;//b++;c++;d++;return a + b + c + d;};
func4();
cout << a << " " << b << " " << c << " " << d << endl;// 混合捕捉2
auto func5 = [=, &a, &b] {a++;b++;/*c++;d++;*/return a + b + c + d;};
func5();
cout << a << " " << b << " " << c << " " << d << endl;

Lambda 表达式的应用场景

常见应用

  • 排序函数中的比较器:利用 lambda 表达式可简化排序代码。
  • 自定义线程执行函数:lambda 可定义线程任务,便于封装。
  • 智能指针的删除器:lambda 表达式可以方便地作为 unique_ptr 等的自定义删除器。

示例:用于商品排序的 Lambda 表达式

相当于直接替代仿函数来使用。

struct Goods {std::string name;double price;int rating;Goods(const std::string &n, double p, int r) : name(n), price(p), rating(r) {}
};std::vector<Goods> items = {{"苹果", 2.5, 5}, {"橙子", 3.0, 4}, {"香蕉", 1.5, 3}};// 使用 lambda 表达式按价格升序排序
std::sort(items.begin(), items.end(), [](const Goods &a, const Goods &b) {return a.price < b.price;
});

Lambda 表达式的原理

Lambda 表达式在底层通过创建一个仿函数对象来实现。当我们定义一个 lambda 表达式时,编译器会生成一个包含捕捉列表和函数体的匿名类,lambda 表达式实际上是该类的一个 operator(),底层是仿函数对象。

汇编层的实现

通过汇编代码可看到,lambda 表达式生成的对象会自动调用 operator(),并且捕捉的变量会作为构造函数的参数。如下所示:

class Rate
{
public:Rate(double rate): _rate(rate){}double operator()(double money, int year){return money * _rate * year;}private:double _rate;
};int main()
{double rate = 0.49;// lambdaauto r2 = [rate](double money, int year) {return money * rate * year;};// 函数对象Rate r1(rate);r1(10000, 2); // 仿函数r2(10000, 2); // lambdaauto func1 = [] {std:: cout << "hello world" << std::endl;};func1();return 0;
}

call的内容不难看出lambda的底层就是仿函数。

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

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

相关文章

Docker平台搭建方法

Docker平台搭建方法 1.1在VMware中创建两个虚拟机&#xff0c;只需要1个网卡&#xff0c;连接192.168.200.0网络。 虚拟机分配2个CPU,2G内存&#xff0c;60G硬盘&#xff0c;主机名分别为server和client,IP地址分别为192.168.200.137和192.168.200.138。server节点还兼做regis…

【学习笔记】Kylin-Desktop-V10-SP1 麒麟系统知识4——设备设置

提示&#xff1a;学习麒麟Kylin-Desktop-V10-SP1系统设备设置相关知识&#xff0c;包含设备设置进入方法、配置打印机、设置鼠标、键盘相关参数&#xff08;包含输入法的配置&#xff09;、以及管理快捷键组合、和多屏协同相关配置 一、前期准备 成功安装麒麟系统&#xff08…

Linux应用项目之量产工具(一)——显示系统

目录 前言 项目特点及介绍 ① 简单易用 ② 软件可配置、易扩展 ③ 纯 C 语言编程 软件总框架 显示系统 1.数据结构抽象 disp_manager.h 2.Framebuffer编程 framebuffer.c 3.显示管理 disp_manager.c 4.单元测试 disp_test.c 顶层目录Makefile 顶层目录Makefil…

企微SCRM价格解析及其性价比分析

内容概要 在如今的数字化时代&#xff0c;企业对于客户关系管理的需求日益增长&#xff0c;而企微SCRM&#xff08;Social Customer Relationship Management&#xff09;作为一款新兴的客户管理工具&#xff0c;正好满足了这一需求。本文旨在为大家深入解析企微SCRM的价格体系…

leetcode92:反转链表||

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1a;[1,4,3,2…

Python——数列1/2,2/3,3/4,···,n/(n+1)···的一般项为Xn=n/(n+1),当n—>∞时,判断数列{Xn}是否收敛

没注释的源代码 from sympy import * n symbols(n) s n/(n1) print(数列的极限为&#xff1a;,limit(s,n,oo))

多线程的创建方式以及及Thread类详解

目录 一.线程的创建方法&#xff1a;&#xff08;重点&#xff09; 一&#xff1a;继承Thread类 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 二.实现Runnable接口 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 三. 实现 Callable 接口 ​…

成功解决WSL2上的Ubuntu22.04执行sudo apt-get update指令报错问题

问题&#xff1a;输入sudo apt-get update指令会显示如下报错 问题所在&#xff1a;Temporary failure in name resolution 显然是系统无法解析域名。这可能是 DNS 配置问题。 解决方案&#xff1a; 临时修改 DNS 配置 尝试手动修改 /etc/resolv.conf 文件来使用公共 DNS 服务…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-19

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

ffmpeg 视频滤镜:屏蔽边框杂色- fillborders

滤镜描述 fillborders 官网链接 > FFmpeg Filters Documentation fillborders滤镜有几种方式帮你屏蔽边框的杂色、不好的图案。 滤镜使用 参数 left <int> ..FV.....T. set the left fill border (from 0 to INT_MAX) (default 0)right …

Unity性能优化 -- 性能分析工具

Stats窗口Profiler窗口Memory Profiler其他性能分析工具&#xff08;Physica Debugger 窗口&#xff0c;Import Activity 窗口&#xff0c;Code Coverage 窗口&#xff0c;Profile Analyzer 窗口&#xff0c;IMGUI Debugger 窗口&#xff09; Stats 统级数据窗口 game窗口 可…

【Ant.designpro】上传图片

文章目录 一、前端二、后端 一、前端 fieldProps:可以监听并且获取到组件输入的内容 action{“/api/upload_image”} 直接调用后端接口 <ProFormUploadButtonlabel{"上传手续图片"}name{"imgs"}action{"/api/upload_image"}max{5} fieldPro…

王珊数据库系统概论第六版PDF+第五版课后答案+课件

为了保持科学性、先进性和实用性&#xff0c; 编者在第5版教材基础上对全书内容进行了修改、更新和充实。在科学性方面&#xff0c; 编者在系统篇中增加了第9章关系数据库存储管理&#xff0c; 讲解数据库的逻辑与物理组织方式及索引结构。增加这部分内容有助于学生更好地理解关…

胡闹厨房练习(一)

参考教程 参考教程 学习视频 目录 准备工作 一、创建项目 二、处理预置文件和设置 三、编辑器布局 四、Visual Studio设置 五、导入资源 六、设置源素材 七、视觉效果&#xff08;后期处理&#xff09; 角色控制器 一、角色 二、制作动画 三、动画控制 四、运动脚…

「QT」几何数据类 之 QVector2D 二维向量类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

Spring中的过滤器和拦截器

Spring中的过滤器和拦截器 一、引言 在Spring框架中&#xff0c;过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是实现请求处理的两种重要机制。它们都基于AOP&#xff08;面向切面编程&#xff09;思想&#xff0c;用于在请求的生命周期…

网站架构知识之Ansible模块(day021)

1.Ansible模块 作用:通过ansible模块实现批量管理 2.command模块与shell模块 command模块是ansible默认的模块&#xff0c;适用于执行简单的命令&#xff0c;不支持特殊符号 案列01&#xff0c;批量获取主机名 ansible all -m command -a hostname all表示对主机清单所有组…

requestAnimationFrame与setInterval的抉择

&#x1f64c; 如文章有误&#xff0c;恳请评论区指正&#xff0c;谢谢&#xff01; ❤ 写作不易&#xff0c;「点赞」「收藏」「转发」 谢谢支持&#xff01; 背景 在之前的业务中遇到有 JS 动画的实现场景&#xff0c;但当电脑打开太多网页或是同时启动很多应用时&#xff0c…

高性能分布式缓存Redis-分布式锁与布隆过滤器

一、分布式锁 我们先来看一下本地锁 在并发编程中&#xff0c;我们通过锁&#xff0c;来避免由于竞争而造成的数据不一致问题。通常&#xff0c;我们以 synchronized 、Lock 来使用它&#xff08;单机情况&#xff09; 来看这段代码 Autowired RedisTemplate<String,Str…

Flutter运行App时出现“Running Gradle task ‘assembleDebug“问题解决

在参考了众多解决办法中最有用并且最快的方法 Gradle Distributions 在这个地方下载对应你这个文件中的gradle版本 然后将 最后一行本来不是这样的,我们把下载好的zip包保存到本地,然后用这个代替网址,最后成功运行