C++11中重要的新特性之 lambda表达式 Part two

序言

 在上一篇文章中,我们主要介绍了 C++11 中的新增的关键词,以及 范围for循环 这类语法糖的使用和背后的逻辑。在这篇文章中我们会继续介绍一个特别重要的新特性分别是 lambda表达式


1. lambda表达式

1.1 lambda的定义

C++11 中的 lambda表达式 是一种定义 匿名函数对象 的方式。它们可以捕获它们所在作用域中的变量,并且可以在需要函数对象的地方使用,如作为算法的参数。lambda表达式C++11 标准引入后,大大简化了编码并增强了代码的灵活性和可读性。我们在这里提到 匿名函数对象,说直白点就是该函数没有具体名字嘛,那是真的没有吗?请大家记住这个疑问。

1.2 lambda表达式的基本语法

lambda表达式 的基本语法如下:

[capture](parameters) mutable -> return_type { body }
  • capture:捕获列表,指定 lambda表达式 体内部可以访问的外部变量。
  • parameters:参数列表,与普通函数的参数列表类似,但 lambda表达式 也可以没有参数。
  • mutable:可选的,表示代码可以修改以值捕获的外部变量。默认情况下,这些变量是只读的。
  • return_type:返回类型,可选。编译器可以根据内容 自动推导返回类型
  • body:表达式的函数体,可以包含任意有效的C++语句。

我们简单的举一个示例:

void test_1() {auto func1 = [](int A, int B) ->int { return A + B; };cout << func1(1, 2) << endl;
}

我们返回值在没有什么特殊需求下完全是可以省略的,编译器会自动推导,所以我们还可以表示为:

void test_1() {auto func1 = [](int A, int B) { return A + B; };cout << func1(1, 2) << endl;
}

在这里我们的代码逻辑还是比较简单的,当我们的代码逻辑比较复杂时,我们还可以表示为:

void test_1() {auto func1 = [](int A, int B) {  ...... //body};
}

1.3 参数详解

1. capture 捕获列表

 捕捉列表描述了上下文中那些数据可以被 lambda 使用,以及使用的方式传值还是传引用。
举个栗子:

int A = 1, B = 2, C = 1;
auto func2 = [A]() { cout << A << endl; };
func2();

这里就是告诉编译器你可以使用 A变量,当然了,你想让他用谁就放谁到捕获列表中:

int A = 1, B = 2;
auto func2 = [A,B]() { cout << A << endl; cout << B << endl;};
func2();

在这里 [] 的用法可以简单总结为 3 种:

  • [var]:表示值传递方式捕捉变量 var
  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)

注意:父作用域指包含 lambda函数 的语句块

上述的方法甚至还可以混合使用:

int A = 1, B = 2, C = 3;
// 除了 C 都是值传递,而 C 是引用传递
auto func2 = [=, &C](){// };// 除了 C 都是引用传递,而 C 是值传递
auto func3 = [&, C](){// };

2. parameters 参数列表

 参数列表的用法和函数的参数列表都是一致的,没有什么区别。但是如果你没有需要传递的参数时,甚至可以省去:

auto func3 = [A] { cout << A << endl; };

3. mutable 可变的

 当我们的表达式尝试改变 以值捕获 的外部变量时,编译器会报错,比如:

auto func3 = [A] () { ++A; };

这是因为编译器规定这些变量只是可读的,如果你想要进行相应的修改,需要加上 mutable

auto func3 = [A] () mutable { ++A; };

但是这个修改并不会影响 A 本身的的大小,因为是 深拷贝,所以你需要修改 A 本身的大小的话使用引用会更好。

4. return_type 返回类型

 如果你没什么需要特殊需要的话,完全可以省去,因为编译器会自动推导,那什么时候是特殊的需求呢,就比如:

double A = 1.5, B = 2.5, C = 3;
auto func2 = [A, B] () -> int{return A * B;};
cout << func2() << endl;

在这里两个 double 变量相乘推导出肯定是返回 double,但是我想要返回 int 这就可以指定返回类型。

5. body 函数体

 在函数体中,你可以使用参数列表以及捕获列表中的变量。


1.4 lambda 背后的逻辑

 我们是怎么使用仿函数的呢?就比如一下比较大小的仿函数:

template<class T>
struct Less{bool operator()(const T& left, const T& right){left < right;}
};Less<int> less;
int A = 1, B = 0;
less(A, B);

我们在使用该仿函数之前,先使用创建了一个相应的对象,然后再使用。

再看看我们的 lambda 表达式,我们也是先创建一个变量再通过该变量来调用:auto func = [](){}; 。 但是我们在前面说过, lambda表达式 是一种定义 匿名函数对象 的方式。所有他是真的没有名字吗,不是的,他在背后其实编译器给他取了个名字的,只是我们不需要知道,我们只需要使用 auto 接受接好了,不需要管他叫什么。

那怎么证明呢?我们看看汇编层的逻辑:
在这里插入图片描述
很明显是由他是有名字的,只是只有编译器知道而已。
所以,定义了一个 lambda表达式,编译器会自动生成一个类,在该类中重载了 operator()


2. lambda 的使用场景

2.1 sort 函数

 如果我们需要对自定义类型进行排序,举个例子:

class Man {
public:Man(string name, int age) {_name = name;_age = age;}string _name;int _age;
};void test_2() {vector<Man> v;v.emplace_back("L", 10);v.emplace_back("M", 11);v.emplace_back("N", 12);sort(v.begin(), v.end());
}

这样会报错,因为自定义类型不可以直接比较,我们在以前的解决方案可以是写一个仿函数,告诉编译器怎么比较呀:

struct LessForMansAge {bool operator()(const Man& left, const Man& right) {return left._age < right._age;}
};

现在的话,我们可以直接写一个仿函数:

auto Less = [](const Man& left, const Man& right) { return left._age < right._age; };
sort(v.begin(), v.end(), Less);

2.2 for_each 函数

for_each 函数是 C++ 标准库中的一个算法,它定义在头文件 中。这个函数用于对给定范围内的每个元素执行一个指定的操作。for_each 算法提供了一个便利的、统一的方法来遍历容器(或其他支持迭代器的范围),并对每个元素执行某个操作,而不需要显式地编写循环代码。
举个例子,我想要让数组内的元素 * 2 ,并打印结果:

void test_3() {vector<int> v = { 1, 2, 3, 4, 5, 6 };for_each(v.begin(), v.end(), [](int& x) { x *= 2; });for_each(v.begin(), v.end(), [](int& x) { cout << x << endl; });
}

3. 总结

lambda表达式 的语法更加直观和灵活,特别是在处理简单函数或回调函数时。它允许开发者直接在表达式中捕获外部变量,并定义函数体,这使得代码更加易于编写和理解。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

bug - while parsing file included at

bug 如下 找到这个对应文件tb_top.sv的对应行&#xff0c;发现是一个 include "inc_tb_tests_xxx.sv" 问题点&#xff1a;头文件&#xff0c;重复定义&#xff0c;那么 解决方法- 在被include的文件首尾加入 ifndef MY_TRANSACTION__SV define MY_TRANSACTION__SV …

数据库管理 常用函数,处理查询,管理表记录

常用函数 MySQL服务内置命令 语法&#xff1a;函数名(表头名) 可以单独用&#xff0c;也可以镶嵌 select day(now()) select格式: SELECT 函数(表头名) FROM 库名.表名&#xff1b;SELECT 函数(表头名) FROM 库名.表名 WHERE 条件&#xff1b; departments 部门…

hf-mirror (huggingface 的国内镜像)

官网&#xff1a; https://hf-mirror.com/ 网站域名 hf-mirror.com&#xff0c;用于镜像 huggingface.co 域名。作为一个公益项目&#xff0c;致力于帮助国内AI开发者快速、稳定的下载模型、数据集。 如何使用HF-Mirror 方法一&#xff1a;网页下载 在https://hf-mirror.com/…

Linux下常见压缩文件tar.xz、tar.bz2、tar.gz的区别

文章目录 tar.xz tar.bz2 tar.gz 的区别三种文件的解压方式tar.xz的解压 tar.xz tar.bz2 tar.gz 的区别 这三个文件扩展名都表示压缩后的档案文件&#xff0c;但它们使用不同的压缩算法。 tar.xz: tar 代表 Tape Archive&#xff0c;它是一种将多个文件打包成一个文件的工具。…

最新的数据防泄密方案来袭!

沙箱技术作为一种先进的数据安全解决方案&#xff0c;在数据防泄密领域发挥着日益重要的作用。它通过构建一个隔离的虚拟环境&#xff0c;使得应用程序在该环境中运行&#xff0c;从而隔离了应用程序对系统资源的直接访问&#xff0c;有效防止了数据泄露的风险。 一、沙箱技术在…

AI知识库:以AI之力,引领企业知识管理新纪元

在当今这个信息爆炸的时代&#xff0c;企业面临着前所未有的知识管理挑战。随着数据量的激增&#xff0c;如何高效地整理、存储并快速检索海量信息&#xff0c;成为了每个企业亟需解决的核心问题。 在过去&#xff0c;企业的知识库常常被视为一种必要的负担。它们充满了冗长复…

研讨会预告:NVIDIA 携手西门子共创工业元宇宙未来

研讨会预告&#xff1a;NVIDIA 携手西门子共创工业元宇宙未来 来自 NVIDIA 与西门子的专家将在 7 月 16 日举办的研讨会“NVIDIA 携手西门子共创工业元宇宙未来”上共同探讨如何利用 OpenUSD 和生成式 AI 赋能新质生产力&#xff0c;与大家共同走进工业元宇宙的世界&#xff0…

AMEYA360:国民技术推出多款高能专用MCU产品

2024年7月8日&#xff0c;国民技术推出多款高能专用MCU产品。N32H482(通用控制)、N32H487(高性能互联)、N32GH473(电机控制)、N32H474(数字电源控制)四大系列高性能MCU新品&#xff0c;以及基于Arm Cortex M0内核实现的N32G052系列高性价比通用MCU新品。 全新一代高性能MCU新品…

抖音工具箱功能菜单解析分享

一 支持视频链接 采集/点赞/评论/收藏 二 支持导入 用户id私信 内容自定义 可 关注后私信对方 私信间隔自定义 三 支持多直播间 发言 内容-间隔自定义 五 支持 监听指定用户作品 新发作品 自动 点赞/评论/收藏 六 支持 视频评论实时监控 新发评论自动采集获取 七 智能 暂停…

SpringBoot应用配置桥接Prometheus入门

SpringBoot应用配置Prometheus步骤 SpringBoot应用依赖要求PrometheusGrafanaGrafana监控界面模板 SpringBoot应用依赖要求 <!-- 监控系统健康情况的工具 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot…

私域运营从0到1冷启动

私域社群的冷启动是一个从无到有的过程&#xff0c;需要策略和耐心来吸引并维护用户。以下是一些步骤和策略&#xff0c;可以帮助你的私域社群实现从0到1的冷启动&#xff1a; 1. **明确目标和定位**&#xff1a; - 确定社群的目标用户和他们的需求。 - 明确社群的主题和…

3、视图和模板

续上一篇&#xff0c;这一篇 着重于创建公共接口——“视图” 第三部分——3、视图和模板 1、概述2、编写更多视图原理——django依次访问了什么文件 3、写一个真正有用的视图一个快捷函数 render() render——渲染 4、抛出404错误一个快捷函数 get_object_or_404() 5、使用模…

PHP酒店宾馆民宿多商户版系统小程序源码

解锁酒店新境界&#xff01;揭秘多商户版系统的无限可能&#x1f3e8;✨ &#x1f680; 开篇&#xff1a;酒店业的新革命&#xff0c;多商户版系统来袭&#xff01; 你是否梦想过将你的酒店打造成一个集餐饮、娱乐、购物于一体的综合型休闲空间&#xff1f;现在&#xff0c;这…

mysql8多值索引

MySQL8新出了一个多值索引&#xff0c;我还没体验过呢&#xff0c;今天试一试。 建表 我先建个表试一试多值索引的效果。我粗略地看了下多值索引的介绍&#xff0c;发现是只适用于数组类型的。所以我建一个含有数组字段的表试一试。语法还是挺麻烦的&#xff1a; create tabl…

系统架构设计师教程 第二章 计算机系统基础知识-2.4嵌入式系统及软件

系统架构设计师教程 第二章 计算机系统基础知识-2.4嵌入式系统及软件 2.4 嵌入式系统及软件2.4.1 嵌入式系统的组成及特点2.4.1.1 嵌入式系统的组成2.4.1.2 嵌入式系统的特点2.4.2 嵌入式系统的分类2.4.3 嵌入式软件的组成及特点2.4.3.1 嵌入式软件的组成2.4.3.2 嵌入式软件的主…

密态计算,大模型“用数”的必由之路

文&#xff5c;白 鸽 编&#xff5c;王一粟 今年世界人工智能大会上&#xff0c;大模型如何走向深度应用成为重要议题。 但在大模型迈向深度应用的过程中&#xff0c;相比于算力的稀缺&#xff0c;“真正的问题是缺数据&#xff0c;无论是在通用技术领域&#xff0c;还是在专…

最优化方法_高等教育出版社

contents 前言第一章 基本概念1.1 最优化问题简介1.2 凸集和凸函数1.2.1 凸集1.2.2 凸函数1.2.3 凸规划&#xff08;个人补充&#xff09; 1.3 最优性条件1.3.1 下降方向1.3.2 充分必要条件1.3.3 拉格朗日乘子法 1.4 最优化方法概述1.4.1 初始点的选取1.4.2 迭代点好坏的判定1.…

软航文档控件VUE示例运行及控件替换方法记录

目录 示例运行 步骤一、npm install 步骤二、npm run dev 软航文档控件替换 附 vue小白记录一下软航文档控件VUE示例的运行方法以及示例中控件的替换过程。 示例运行 在已经安装好VUE环境的电脑上&#xff0c;VUE环境部署可以参考另一篇&#xff1a;配置VUE环境过程中 …

外卖霸王餐怎么做才能盈利赚钱的呢?

在当前的餐饮市场中&#xff0c;外卖行业已成为不可忽视的一部分&#xff0c;而“外卖霸王餐”作为一种促销策略&#xff0c;更是在外卖市场中引起了广泛的关注。那么&#xff0c;如何通过外卖霸王餐实现盈利赚钱呢&#xff1f;以下将从多个方面进行深入探讨。 一、明确外卖霸王…

仓库的数据管理如何做?

在当今这个数字化飞速发展的时代&#xff0c;仓库作为供应链的核心环节&#xff0c;其数据管理的重要性日益凸显。一个高效、精准的仓库数据管理体系&#xff0c;不仅能够显著提升物流效率&#xff0c;降低运营成本&#xff0c;还能增强企业的市场竞争力。那么&#xff0c;仓库…