C++的lambda语法

仿函数的最大缺点是:

  1. 如果命名不合规范并且没有给出注释,直接阅读难以理解(排序的调用过程中,不查看仿函数细节,则很难直接得知是升序排序还是降序排序)
  2. 每次实现仿函数都需自己构建一个类

因此C++从其他语言借鉴了lambda表达式语法,让我们可以无需提前创建类,提高代码可读性。

1.lambda表达式的语法

lambda表达式的格式为:[capture-list](parameters)mutable->return-type{statement}

  • capture-list:捕捉列表,编译器识别[]判定是否为lambda函数,因此[]不可省略。而捕捉列表本身可以根据父域(对于lambda函数内的变量来说的父域)的上下文,获取变量供lambde函数使用
  • parameters:参数列表,和函数的参数列表基本一致,可以为空
  • mutable:这是一个关键字,意思为“可变的/易变的”,默认情况下,lambda函数总是类似const函数的行为(除非使用引用捕捉,就不会有const行为),而使用该关键字可以取消const行为,并且参数列表此时不能忽略
  • return-type:返回值类型,和普通函数基本类似,没有返回值时可以省略,若返回值明确也会自动推导,也可以省略
  • statement:函数体,内部可以使用参数列表中的参数和捕获的变量列表

lambda函数定义中,也具有函数签名的特征,并且参数列表和返回值类型是可选部分,而捕捉列表和函数体可以为空。

因此最简单的lambda函数为[]{},这个lambda函数不能做任何事情。

2.lambda表达式的运用

让我们尝试使用lambda表达式来书写一个Add()

#include <iostream>
using namespace std;
int main()
{auto add = [](int x, int y)->int { return x + y; };//整体代表一个 lambda 对象cout << [](int x, int y)->int { return x + y; }(1, 2) << endl;cout << add(1, 2) << endl;return 0;
}

而使用lambda表达式就可以替代仿函数在sort()中的使用:

#include <iostream>
#include "Date.hpp" //以前写的 Date 类
using namespace std;
int main()
{vector<Date> v = { { 2013, 7, 9 }, { 2022, 6, 5 }, { 2023, 4, 17 } };auto less = [](const Date& d1, const Date& d2)->bool { return d1 < d2; };sort(v.begin(), v.end(), less);return 0;
}

那捕捉列表怎么用呢?假设我们需要一个交换函数,使用lambda有两种方式书写。

#include <iostream>
using namespace std;
int main()
{//1.设置用于交换的数int x = 10, y = 5;cout << "x=" << x << " " << "y=" << y << '\n';//2.用于交换的 lambda 表达式(指针参数版)auto swap1 = [](int* px, int* py){int tmp = *px;*px = *py;*py = tmp;};swap1(&x, &y);cout << "x=" << x << " " << "y=" << y << '\n';//3.用于交换的 lambda 表达式(引用参数版)auto swap2 = [](int& rx, int& ry){int tmp = rx;rx = ry;ry = tmp;};swap2(x, y);cout << "x=" << x << " " << "y=" << y << '\n';//4.用于交换的 lambda 表达式(列表捕捉版)auto swap3 = [&x, &y](){int temp = x;x = y;y = temp;};swap3();cout << "x=" << x << " " << "y=" << y << '\n';return 0;
}

而捕捉列表可以有多种语法形式来捕捉:

//特定
auto func1 = [x, y](){};//对应变量传值捕捉
auto func2 = [&x, &y](){};//对应变量引用捕捉(需要注意不要误认为是取地址)
auto func3 = [&x, y](){};//对应变量引用+对应变量传值混合捕捉//泛指
auto func4 = [&](){};//所有变量均可引用捕捉(包括 this)
auto func5 = [=](){};//所有变量均可传值捕捉(包括 this)
auto func6 = [&, x](){};//除了 x 参数是传值捕捉,其他都是引用捕捉
auto func7 = [this](){};//捕获当前的 this 指针

3.lambda表达式的误解

  1. lambda表达式的捕获列表只能捕获父域的变量,如果在父域内没有对应的变量,则会编译报错。注意,这个父域是对于lambda内部的来说的,包含lambda表达式所处的表达式

    #include <iostream>
    using namespace std;
    int main()
    {//交换int x = 10, y = 5;cout << "x=" << x << " " << "y=" << y << '\n';do {do {auto swap = [&x, &y](){int temp = x;x = y;y = temp;};swap();} while (0);} while (0);cout << "x=" << x << " " << "y=" << y << '\n';return 0;
    }
    
  2. lambda表达式产生的lambda对象不允许相互赋值,这涉及到底层实现,不同的或者说哪怕相同的lambda表达式结构生成的对象的类型均不一样,并且在不同编译器上运行都不一样(有些编译器的实时可能会看不出来)

    #include <iostream>
    using namespace std;
    int main()
    {//交换int x = 10, y = 5;auto swap1 = [&x, &y](){int temp = x;x = y;y = temp;};auto swap2 = [&x, &y](){int temp = x;x = y;y = temp;};cout << typeid(swap1).name() << '\n';cout << typeid(swap2).name() << '\n';//swap1 = swap2; //报错return 0;
    }
    
  3. lambda对象虽然不允许赋值,但是允许拷贝构造出一个新副本

    #include <iostream>
    using namespace std;
    int main()
    {//交换int x = 10, y = 5;auto swap = [&x, &y](){int temp = x;x = y;y = temp;};auto swapCopy(swap);cout << typeid(swap).name() << '\n';cout << typeid(swapCopy).name() << '\n';return 0;
    }
    
  4. 可以将lambda表达式赋值给和lambda返回值相同类型的函数指针(但是带有捕捉列表的lambda表达式不允许这么做)

    #include <iostream>
    using namespace std;
    void(*p)(int, int);
    int main()
    {//交换int x = 10, y = 5;auto swap = [](int x, int y){cout << "x = " << x << '\n';cout << "y = " << y << '\n';};p = swap;(*p)(x, y);return 0;
    }
    
    #include <iostream>
    using namespace std;int main()
    {//交换int x = 10, y = 5;//lambda表达式没有捕获列表,可以直接赋值给函数指针auto func1 = []() { cout << "Hello, World!" << endl; };void(*ptr1)() = func1;ptr1(); //输出:Hello, World!//lambda表达式带有捕获列表,无法直接赋值给函数指针//int(*ptr2)() = [x, &y]() { return x + y; }; //编译错误return 0;
    }
    
  5. 如果是引用捕捉,无需使用关键字mutable也可以在lambda表达式内修改。也就是说,捕捉变量实际上是一个变量拷贝了父域的变量,而引用则直接使用该变量(不过,如果一个是引用捕捉一个传值引用,就还是需要加上mutable

    #include <iostream>
    using namespace std;
    int main()
    {//交换int x = 10, y = 5;//auto func = [&x, y]()//    {//        x = 0;//        y = 0;//出错,不允许改变//    };auto func = [&x, y]()mutable //必须使用 mutable{x = 0;y = 0;//只是改变了局部变量};func();cout << "x = " << x << endl; //输出 x = 0cout << "y = " << y << endl; //输出 y = 5return 0;
    }
    
  6. this的传值可以让lambda表达式成为类似成员函数的存在写入类中

    #include <iostream>
    using namespace std;class Data
    {
    public:void function(){auto func = [this](){cout << "x = " << x << ", y = " << y << '\n';x = 100;y = 500;cout << "x = " << x << ", y = " << y << '\n';};func();}private:int x = 10;int y = 50;
    };
    int main()
    {Data d;d.function();return 0;
    }
    

4.lambda表达式的疑问

我们的确可以使用lambda表达式解决了使用sort(v.begin(), v.end(), less)的问题,但是我们还有一种情况会使用仿函数,就是在使用map的时候会写出map<string, int, 仿函数类类型>,对最后的仿函数需要将string转化为key,但是仿函数的类型我们尚且可以知道,那么lambda怎么办呢?

lambda的类型比较难以获取,并且还是匿名的,尽管有些其他的办法获取类型,但是我们更加推荐使用包装类function{},这些我们下一篇介绍。

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

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

相关文章

分类详情 API 返回值说明

为了进行此平台API的调用&#xff0c;首先我们需要做下面几件事情。 1、 获取一个KEY&#xff0c;点击获取测试key和secret 2、 参考API文档里的接入方式和示例。 3、查看测试工具是否有需要的接口&#xff0c;响应实例的返回字段是否符合参数要求。 4、利用平台的文档中心…

[前 5 名] 最顶级的数据恢复软件解决方案列表

您是否在互联网上找到适用于 Windows PC 的前 5 名最受好评的数据恢复软件解决方案&#xff1f;嗯&#xff0c;在线市场上有很多工具可以恢复已删除的文件。但并不是所有的应用程序都值得使用它。值得信赖的文件恢复工具将有助于快速检索丢失、删除、格式化的数据并从计算机恢复…

JVM之基本概念(一)

(1) 基本概念&#xff1a; JVM 是可运行 Java 代码的假想计算机 &#xff0c;包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。 (2) 运行过程&#xff1a; 我们都…

[传智杯 #4 决赛] 小智的疑惑

题目描述 传智专修学院给了小智一个仅包含小写字母的字符串 s&#xff0c;他想知道&#xff0c;里面出现了多少次子串 chuanzhi 呢。 我们称一个字符串 t 是 s 的子串&#xff0c;当且仅当将 s 的开头若干个&#xff08;可以为 0 个&#xff09;连续字符和结尾若干个&#xf…

讲一下mysql的锁

MySQL 中的锁机制是数据库管理系统用于控制并发访问的重要组成部分。锁是一种资源访问的机制&#xff0c;通过它可以确保在同一时间只有一个事务能够对资源进行操作&#xff0c;从而维护数据的一致性和完整性。在 MySQL 中&#xff0c;锁主要分为共享锁&#xff08;Shared Lock…

听GPT 讲Rust源代码--src/tools(7)

File: rust/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs 在Rust源代码中&#xff0c;rust-analyzer/crates/ide/src/inlay_hints/chaining.rs这个文件的作用是生成Rust代码中的链式调用提示。 具体来说&#xff0c;当我们使用链式调用时&#xff0c;例如A…

Python练习题(三)

&#x1f4d1;前言 本文主要是【Python】——Python练习题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

51单片机PWM讲解

前言 51单片机我已经很久没用过了&#xff0c;毕竟是十年前的产物了&#xff0c;但是由于工作室的学弟学妹需要学习&#xff0c;加之马上就要举行循迹小车比赛&#xff0c;很多人反映看不懂PWM&#xff0c;或者看了不会用&#xff0c;于是写一篇文章简单介绍一下。 PWM普遍应…

Kubernetes学习笔记-Part.08 安装k8s环境

目录 Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退 第八章 K8s环境安装 8.1.准备安装文件 在外网服务器…

IDEA如何配置Git 遇到问题的解决

新建项目 点击 会变红 会生成.git隐藏文件 配置远程仓库路径&#xff1a;点击Manage Remotes&#xff1a;将远程仓库的链接放到这里&#xff1a; 得到如下样式&#xff1a; 此时提交到本地仓库 点击add&#xff0c;添加到暂存文件&#xff1a; 此时文件变绿&#xf…

【Ratis】Grpc.proto文件里定义的一些RPC

一、 总览 Raft的提供了三种类型的RPC。分别如下&#xff1a; RaftClientProtocolService&#xff1a;client与server之间的交互RPC&#xff0c;分为ordered和unordered&#xff0c;一种是有序的异步请求流、一种是无序的异步请求流。RaftServerProtocolService&#xff1a;r…

JDK中lock锁的机制,其底层是一种无锁的架构实现的,公平锁和非公平锁

简述JDK中lock锁的机制&#xff0c;其底层是一种无锁的架构实现的&#xff0c;是否知道其是如何实现的 synchronized与lock lock是一个接口&#xff0c;而synchronized是在JVM层面实现的。synchronized释放锁有两种方式&#xff1a; 获取锁的线程执行完同步代码&#xff0c;…

Elasticsearch一些函数查询

1. 根据价格分组统计数量&#xff0c;每组区间为2000&#xff0c; filter_pathaggregations 设置查询结果只展示函数结果 也有date_histogram函数根据日期分组等等 GET order/_search?filter_pathaggregations {"aggs": {"hist_price": {"histogr…

神经网络 代价函数

神经网络 代价函数 首先引入一些便于稍后讨论的新标记方法&#xff1a; 假设神经网络的训练样本有 m m m个&#xff0c;每个包含一组输入 x x x和一组输出信号 y y y&#xff0c; L L L表示神经网络层数&#xff0c; S I S_I SI​表示每层的neuron个数( S l S_l Sl​表示输出…

使用idea如何快速的搭建ssm的开发环境

文章目录 唠嗑部分言归正传1、打开idea&#xff0c;点击新建项目2、填写信息3、找到pom.xml先添加springboot父依赖4、添加其他依赖5、编写启动类、配置文件6、连接创建数据库、创建案例表7、安装MybatisX插件8、逆向工程9、编写controller10、启动项目、测试 结语 唠嗑部分 小…

MIT线性代数笔记-第21讲-特征值,特征向量

目录 21.特征值&#xff0c;特征向量打赏 21.特征值&#xff0c;特征向量 对于一个方阵 A A A&#xff0c;若 A x ⃗ λ x ⃗ A \vec{x} \lambda \vec{x} Ax λx &#xff0c;即 A x ⃗ A \vec{x} Ax 平行于 x ⃗ \vec{x} x &#xff0c;那么 λ \lambda λ是 A A A的特征值…

怎么防止死锁

目录 一、死锁的概念 1、互斥条件 2、 占有和等待条件 3、非抢占条件&#xff08;No Preemption&#xff09;&#xff1a; 4、环路等待条件&#xff08;Circular Wait&#xff09;&#xff1a; 二、防止死锁 死锁预防&#xff08;Deadlock Prevention&#xff09;&#xf…

内网穿透工具获取一个公网ip

下载地址&#xff1a;点击即可下载很简单 然后将他复制到上面的命令行窗口直接回车

LeetCode1423. Maximum Points You Can Obtain from Cards

文章目录 一、题目二、题解 一、题目 There are several cards arranged in a row, and each card has an associated number of points. The points are given in the integer array cardPoints. In one step, you can take one card from the beginning or from the end of…

Programming Contest 2023(AtCoder Beginner Contest 331)E题 Set Meal --- 题解

目录 E题 Set Meal 题目大意&#xff1a; 思路&#xff1a;&#xff08;在求最大时和最小时&#xff0c;如果要求查询代价较小时&#xff0c;可以使用优先队列&#xff09; 代码&#xff1a; E题 Set Meal E - Set Meal (atcoder.jp) 题目大意&#xff1a; 先给出n个…