【C++】 Lambda表达式详解

news2024/11/27 13:48:40

▒ 目录 ▒

    • 🛫 问题
      • 描述
      • 环境
    • 1️⃣ 什么是Lambda表达式
      • Lambda 表达式的各个部分
    • 2️⃣ 优缺点
      • 优点
      • 缺点
    • 3️⃣ 使用场景
      • 在线C++工具
      • STL算法库
      • STL容器中需要传递比较函数(示例失败了)
      • 多线程示例
    • 4️⃣ Lambda表达式与函数指针的比较
    • 5️⃣ 捕获列表
    • 6️⃣ 返回值类型
    • 7️⃣ 工作原理
    • 📖 参考资料

🛫 问题

描述

记得去年立了一个重学C++新特性的flag,可是真的太忙了,大部分精力都花在全栈上了,今年开始看一些开源源码,发现各种奇怪的语法,根本看不懂,不学不行了。而且接触了很多语言后,发现新特性的确能提高开发效率,所以还是重新学习下C++吧。

环境

版本号描述
文章日期2023-06-09
操作系统Win11 - 21H2 - 22000.1335
C++在线工具https://c.runoob.com/compile/12/

1️⃣ 什么是Lambda表达式

Lambda表达式是C++11中新增的一种函数对象,它可以方便地定义一个匿名函数,从而简化代码的编写。
Lambda表达式的本质是一个可调用对象,可以像函数一样被调用,也可以作为函数参数或返回值。

Lambda 表达式的各个部分

下面是作为第三个参数 std::sort() 传递给函数的简单 lambda:

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
    std::sort(x, x + n,
        // 下面是一个简单的 `Lambda 表达式`
        [](float a, float b) {
            return (std::abs(a) < std::abs(b));
        } 
    ); 
}

下图显示了 lambda 语法的各个部分:

  1. 捕获列表:(capture list)(在 C++ 规范中也称为 Lambda 引导。)
  2. 参数列表:(parameters list)(可选)。 (也称为 Lambda 声明符)
  3. mutable 规范:(可选)。
  4. 异常说明:exception-specification(可选)。
  5. 返回类型:trailing-return-type(可选)。
  6. Lambda 体:也就是函数体。
    标识 lambda 表达式的各个部分的示意图。

引用大佬的一张图:
在这里插入图片描述

2️⃣ 优缺点

优点

  1. 简化代码:Lambda表达式可以将一些冗长的代码简化为一行代码,使代码更加简洁。
  2. 提高可读性:Lambda表达式可以使代码更加易读,减少了一些冗余的代码,使代码更加简洁明了。
  3. 提高可维护性:Lambda表达式可以使代码更加易于维护,因为它可以将一些复杂的逻辑封装在一个方法中,使代码更加模块化。

缺点

  1. 学习成本高:Lambda表达式需要一定的学习成本,需要理解函数式编程的概念和Lambda表达式的语法。
  2. 可读性降低:有时候Lambda表达式可能会使代码变得更加难以理解,特别是当Lambda表达式嵌套时。
  3. 性能问题:Lambda表达式可能会影响程序的性能,因为它需要创建一个新的对象来表示Lambda表达式。但是,这种影响通常是微不足道的,只有在极端情况下才会有明显的性能问题。

3️⃣ 使用场景

Lambda表达式可以用于任何需要函数对象的场景,例如:

  • STL算法中需要传递函数对象的地方,如std::sortstd::for_each等;
  • STL容器中需要传递比较函数的地方,如std::setstd::map等;
  • 多线程编程中需要传递回调函数的地方,如std::threadstd::async等。

在线C++工具

为了方便演示,找了个在线C++工具 https://c.runoob.com/compile/12/ ,可以直接在网页中运行C++代码。
效果图如下:
在这里插入图片描述

STL算法库

find_if应用实例

#include <iostream>
#include <deque>
#include <algorithm>

using namespace std;

int main()
{
	int x = 5;
	int y = 10;
	deque<int> coll = { 1, 3, 19, 5, 13, 7, 11, 2, 17 };
	auto pos = find_if(coll.cbegin(), coll.cend(), [=](int i) {                 
		return i > x && i < y;
	});
	
	cout << "find " << (pos != coll.end() ? "success" : "failed");

   return 0;
}

sort实例,用于对一个整数数组进行排序:
以上代码中,Lambda表达式[](int a, int b) { return a < b; }用于指定排序规则,即按照升序排列。

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};

    // 使用Lambda表达式对vec进行排序
    std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });

    // 输出排序后的结果
    // 1 1 2 3 3 4 5 5 5 6 9 
    for (auto x : vec)
    {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    return 0;
}

STL容器中需要传递比较函数(示例失败了)

下面代码不能在C++在线工具上正常运行,vs2022上也未能正常运行,以后再研究吧,实在没整明白。

#include <iostream>
#include <algorithm>
#include <string>
#include <map>

int main()
{
	auto fc = [](const std::string& a, const std::string& b) {
		return a.length() < b.length();
	};
	std::map<std::string, int, decltype(fc)*> myMap = {{"apple", 5}, {"banana0", 10}, {"orange", 15}};

    // 使用迭代器遍历map
    std::cout << "使用迭代器遍历map:" << std::endl;
    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << it->first << " : " << it->second << std::endl;
    }

    // 使用范围for循环遍历map
    // std::cout << "使用范围for循环遍历map:" << std::endl;
    // for (const auto& [key, value] : myMap) {
    //     std::cout << key << " : " << value << std::endl;
    // }

    return 0;
}

多线程示例

#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>

int main()
{
    // vector 容器存储线程
    std::vector<std::thread> workers;
    for (int i = 0; i < 5; i++) 
    {
        workers.push_back(std::thread([]() 
        {
            std::cout << "thread function\n";
        }));
    }
    std::cout << "main thread\n";

    // 通过 for_each 循环每一个线程
    // 第三个参数赋值一个task任务
    // 符号'[]'会告诉编译器我们正在用一个匿名函数
    // lambda函数将它的参数作为线程的引用t
    // 然后一个一个的join
    std::for_each(workers.begin(), workers.end(), [](std::thread &t;) 
    {
        t.join();
    });

    return 0;
}

4️⃣ Lambda表达式与函数指针的比较

Lambda表达式与函数指针类似,都可以用于定义函数对象。但是,Lambda表达式相比函数指针具有以下优点:

  • Lambda表达式可以捕获外部变量,从而方便地访问外部环境;
  • Lambda表达式可以定义在函数内部,从而避免了命名冲突的问题;
  • Lambda表达式可以使用auto关键字自动推导返回值类型,从而简化代码。

5️⃣ 捕获列表

Lambda表达式的捕获列表用于指定Lambda表达式中使用的外部变量。捕获列表可以为空,也可以包含以下内容:

  • []:不捕获任何外部变量;
  • [&]:以引用方式捕获所有外部变量;
  • [=]:以值方式捕获所有外部变量;
  • [var1, var2, ...]:指定捕获特定的外部变量;
  • [&, var1, var2, ...]:以引用方式捕获所有外部变量,并指定捕获特定的外部变量;
  • [=, &var1, &var2, ...]:以值方式捕获所有外部变量,并以引用方式捕获特定的外部变量。

6️⃣ 返回值类型

Lambda表达式的返回值类型可以显式指定,也可以使用auto关键字自动推导。如果Lambda表达式的函数体只有一条语句,且该语句的返回值类型可以自动推导,则可以省略返回值类型和return关键字。

7️⃣ 工作原理

编译器会把一个Lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法。
auto print = []{cout << "Hello World!" << endl; };为例,编译器会把上面这一句翻译为下面的代码:

class print_class
{
public:
	void operator()(void) const
	{
		cout << "Hello World!" << endl;
	}
};
// 用构造的类创建对象,print此时就是一个函数对象
auto print = print_class();

ps: 仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,仿函数与Lamdba表达式的作用是一致的。
stl中含有大量类似的对象,如std::less
在这里插入图片描述

📖 参考资料

  • 微软Lambda教程 https://learn.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170
  • C++ Lambda表达式详解 https://blog.csdn.net/qq_37085158/article/details/124626913
  • 在线C++工具 https://c.runoob.com/compile/12/

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

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

相关文章

KISS复盘法

KISS复盘法 KISS复盘法是一种科学的项目复盘方法&#xff0c;能够把过往经验转化为实践能力&#xff0c;以促进下一次活动更好地展开&#xff0c;从而不断提升个人和团队的能力&#xff01; 模型介绍 【复盘】原是围棋术语&#xff0c;本意是对弈者在下完一盘棋之后&#xff0…

距离保护原理

距离保护是反映故障点至保护安装处的距离&#xff0c;并根据距离的远近确定动作时间的一种保护。故障点距保护安装处越近&#xff0c;保护的动作时间就越短&#xff0c;反之就越长&#xff0c;从而保证动作的选择性。测量故障点至保护安装处的距离&#xff0c;实际上就是用阻抗…

Spring Boot banner详解

Spring Boot 3.x系列文章 Spring Boot 2.7.8 中文参考指南(一)Spring Boot 2.7.8 中文参考指南(二)-WebSpring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解 自定义banner Spring …

快速排序算法的编码和优化

快速排序的基本思路是&#xff1a; 先通过第一趟排序&#xff0c;将数组原地划分为两部分&#xff0c;其中一部分的所有数据都小于另一部分的所有数据。原数组被划分为2份通过递归的处理&#xff0c; 再对原数组分割的两部分分别划分为两部分&#xff0c;同样是使得其中一部分…

springboot+java高校教材征订管理系统

教材管理系统从功能、数据流程、可行性、运行环境等方面进行需求分析。对教材管理系统的数据库、功能进行了详细设计。分析了主要界面设计和相关组件设计&#xff0c;对教材管理系统的具体实现进行了介绍。 采用Java技术&#xff0c;从数据库中获取数据、向数据库中写入数据&am…

Linux 4.10 将带来深远影响的三项小改变

Linux的演进永不停歇。Linus Torvalds一直在努力工作&#xff0c;希望能够在新的内核版本当中(4.11)融入更多变化。不过在目前的Linux 4.10中&#xff0c;我们同样发现了三组能够有效提升性能并实现多种前所未有功能集的变更。 Linux的演进永不停歇。Linus Torvalds一直在努力…

如何快速写出一个完整的测试用例

一、前言 测试工作中最为基础核心的内容就是设计测试用例&#xff0c;我们一般会认为数量越少、发现缺陷越多的用例就是好的用例。那么&#xff0c;怎样才能设计出好的测试用例呢&#xff1f;本次专题就向大家介绍如何编写一个完整且靠谱的测试用例。 二、测试用例的重要性 …

使用IPSW文件将iOS系统从Beta恢复到稳定正式版教程

起因 作为一名iOS开发者&#xff0c;为了拥抱新系统&#xff08;手贱&#xff09;&#xff0c;将开发机升级到了最新的iOS 17 Beta版本&#xff0c;从而导致使用现有的Xcode无法成功配对该版本系统。故准备想方设法回滚到原先的iOS 16.5稳定版 回滚方式 若要将iOS设备回退至…

【MySQL高级篇笔记-数据库其它调优策略(中) 】

此笔记为尚硅谷MySQL高级篇部分内容 目录 一、数据库调优的措施 1、调优的目标 2、如何定位调优问题 3、调优的维度和步骤 二、优化MySQL服务器 1、优化服务器硬件 2、优化MySQL的参数 三、优化数据库结构 1、拆分表&#xff1a;冷热数据分离 2、增加中间表 3、增加…

CKA 01_docker部署Kubernetes 部署docker 使用kubeadm引导集群 安装Pod网络

文章目录 1. 虚拟机步骤2. Docker 部署 Kubernetes2.1 部署 docker2.1.1 环境要求2.1.2 安装 docker 引擎2.1.3 worker 节点对 master 节点免密2.1.4 设定 docker 开机自启2.1.5 打开桥接&#xff0c;查看桥接流量2.1.6 设定 systemd 方式管理 cgroup2.1.7 docker部署完成2.1.8…

光伏储能直流系统MATLAB仿真(PV光伏阵列+Boost DCDC变换器+负载+双向DCDC变换器+锂离子电池系统)

PV光伏阵列Boost DCDC变换器负载双向DCDC变换器锂离子电池系统 资源地址&#xff1a; 光伏储能直流系统MATLAB仿真&#xff08;PV光伏阵列BoostDCDC变换器负载双向DCDC变换器锂离子电池系统&#xff09;-Matlab文档类资源-CSDN文库 主要模块&#xff1a; PV光伏阵列、Boost…

这 3个Python 函数你知道吗?

动动发财的小手&#xff0c;点个赞吧&#xff01; 作为21世纪最流行的语言之一&#xff0c;Python当然有很多有趣的功能值得深入探索和研究。今天将介绍其中的三个&#xff0c;每个都从理论上和通过实际示例进行介绍。 我想要介绍这些函数的主要原因是它们可以帮助您避免编写循…

CKA 09_Kubernetes工作负载与调度 资源调度 三类QoS request 资源需求 limit 资源限额

文章目录 1. 资源调度1.1 准备工作1.2 为什么需要 request 和 limit1.3 内存限制1.3.1 Brustable1.3.2 Guaranteed1.3.3 BestEffort1.3.4 当容器申请的资源超出 limit 和 request 1.4 CPU限制 1. 资源调度 1.1 准备工作 Kubernetes 采用 request 和 limit 两种限制类型来对资源…

中国电子学会2023年05月份青少年软件编程Python等级考试试卷一级真题(含答案)

2023-05 Python一级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 可以对Python代码进行多行注释的是&#xff1f;&#xff08;C &#xff09; A.# B." " C. D. 2. 下列可以作为Py…

ChatGPT有哪些神奇的使用方式? ChatGPT十大功能

原文&#xff1a;ChatGPT有哪些神奇的使用方式? ChatGPT十大功能_其他工具_软件教程_脚本之家 随着微软、百度等巨头加码&#xff0c;AIGC&#xff08;人工智能自动生成内容&#xff09;领域或将成为2023年最值得关注的、全球最热门赛道。AI大模型相当于是通过积累大量知识&a…

MT6705B 同步整流器

MT6705B 是用于反激式变换器的高性能45V 同步整流器。它兼容各种反激转换器类型。支持 DCM、CCM 和准谐振模式。MT6705B集成了一个40V功率MOSFET&#xff0c;可以取代肖特基二极管&#xff0c;提高效率。V SW <V TH-ON 时&#xff0c;内部 MOSFET 导通。V SW >V TH-OFF 时…

前端响应式布局--更新中

前端响应式布局原理与方案&#xff08;详细版&#xff09; 文章目录 媒体查询Grid布局Flex布局 响应式布局&#xff1a;在不同屏幕尺寸下&#xff0c; 同一页面有不同的布局。 传统的开发模式&#xff1a;PC端搞一套布局&#xff0c;移动端搞一套布局。 使用了响应式布局&#…

SpringBoot中集成Swagger2

介绍 Swagger是非常流行的API框架&#xff0c;能够自动生成RESTFul 风格的API文档&#xff0c;还可以在线测试后台接口。 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息&#xff0c;再通过Swagger衍生出来的一系列项目和工具&#xff0c;就可以做到生成各种格式…

【论文阅读】Language Models are Few-Shot Learners(GPT-3)

前言 本文简要介绍了GPT-3的背景&#xff0c;模型架构&#xff0c;训练数据以及训练方式部分。具体训练细节&#xff0c;实验结果很多&#xff0c;可以在用到的时候再看 Intro 本文剖析了pretrain-finetune架构存在的问题&#xff1a; 对于每个新的任务&#xff0c;都需要大…

kotlin withTimeoutOrNull超时返回

kotlin withTimeoutOrNull超时返回 import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeoutOrNullfun main(args: Array<String>) {testTimeOut(1000) //如果是2000&#xff0c;则正常返回 OK }fun testTimeOut(…