C++11(lambda表达式)

news2024/11/28 7:27:30

目录

一、lambda表达式的引入

二、语法格式

三、捕捉方式

四、lambda表达式的底层 

1、仿函数的调用

2、lambda的调用

​编辑


一、lambda表达式的引入

在之前,我们调用函数的方式有:通过函数指针调用,仿函数也能像函数一样调用。而在C++11中,标准库提供了 lambda 表达式的使用。

在C++98中,如果想要对一个数据集合中的元素进行排序,可以使用std::sort方法。但是如果待排序元素为自定义类型,需要用户定义排序时的比较规则:

如下面我们定义了一个商品的类,然后我们要分别根据价格的升序和降序进行排序,那么我们最先想到的方法就是使用仿函数来帮助我们排序。

struct Goods
{
    string _name;  // 名字
    double _price; // 价格
    int _evaluate; // 评价
    Goods(const char* str, double price, int evaluate)
        :_name(str)
        , _price(price)
        , _evaluate(evaluate)
    {}
};

 降序的仿函数

struct ComparePriceLess
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
        return gl._price < gr._price;
    }
};

升序的仿函数

struct ComparePriceGreater
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
    return gl._price > gr._price;
    }
};

我们测试一下: 

int main()
{
    vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
    3 }, { "菠萝", 1.5, 4 } };

    sort(v.begin(), v.end(), ComparePriceLess());
	for (auto e : v)
	{
		cout << e._name << " ";
	}
    cout << endl;

	sort(v.begin(), v.end(), ComparePriceGreater());
	for (auto e : v)
	{
		cout << e._name << " ";
	}
}

 

我们是不是觉得上面的写法太复杂了,每次为了实现一个algorithm算法,都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这些给我们带来了极大的不便。因此,在C++11语法中出现了Lambda表达式。


二、语法格式

lambda表达式实际是一个匿名函数。

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

[capture-list] : 捕捉列表。可以将已经定义过的与lambda在同一作用域的变量捕捉过来使用。

(parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。

mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。

return-type:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推
导。

{statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注:参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。 

下面我们来举一个例子:写一个计算两数相加的lambda的表达式。

int main()
{
	auto add1 = [](int x, int y)->int{return x + y; };
    cout << add1(1, 2) << endl;

    //省略返回值
	auto add2 = [](int x, int y) {return x + y; };
	cout << add2(1, 2) << endl;

	return 0;
}

三、捕捉方式

Lambda表达式中的捕捉列表捕捉上下文中的变量可以被lambda使用,以及可以设置使用的方式是传值还是传引用:

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

注:
1、父作用域指包含lambda函数的语句块。
2、语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
      比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量
                 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
3、捕捉列表不允许变量重复传递,否则就会导致编译错误。
      比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
4、在块作用域以外的lambda函数捕捉列表必须为空。
5、在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
6、lambda表达式之间不能相互赋值,即使看起来类型相同。


四、lambda表达式的底层 

别看lambda看起来很神奇,其实它的底层就是仿函数来实现的。下面我们来看一看。

我们用下面的代码来验证:

class Rate
{
public:
    Rate(double rate): _rate(rate)
    {}
    double operator()(double month, int year)
    { return month * _rate * year;}
private:
    double _rate;
};
int main()
{
    // 函数对象
    double rate = 0.49;
    Rate r1(rate);
    r1(10000, 2);

    // lambda
    auto r2 = [=](double month, int year)->double{return month*rate*year;};
    r2(10000, 2);

    return 0;
}

1、仿函数的调用

2、lambda的调用

1、从使用方式上来看,函数对象与lambda表达式完全一样。
2、函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可以直接将该变量捕获到。

3、实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

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

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

相关文章

pgsl基于docker的安装

1. 有可用的docker环境 &#xff0c;如果还没有安装docker&#xff0c;则请先安装docker 2. 创建pg数据库的挂载目录 mkdir postgres 3. 下载pg包 docker pull postgres 这个命令下载的是最新的pg包&#xff0c;如果要指定版本的话&#xff0c;则可以通过在后面拼接 :versio…

12 | JPA 的审计功能解决了哪些问题

Auditing 指的是什么&#xff1f; Auditing 是帮我们做审计用的&#xff0c;当我们操作一条记录的时候&#xff0c;需要知道这是谁创建的、什么时间创建的、最后修改人是谁、最后修改时间是什么时候&#xff0c;甚至需要修改记录……这些都是 Spring Data JPA 里面的 Auditing…

【LeetCode刷题(数据结构)】:给定一个链表 返回链表开始入环的第一个节点 如果链表无环 则返回 NULL

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos…

【Eclipse】查看版本号

1.在Eclipse的启动页面会出现版本号 2. Eclipse的关于里面 Help - About Eclipse IDE 如下图所示&#xff0c;就为其版本 3.通过查看readme_eclipse.html文件

华为浏览器风险提示 - 解决方案

问题 使用华为手机自带的华为浏览器时&#xff0c;可能会遇到网页提示风险提示且无法打开的情况&#xff0c;如下图。这是因为华为浏览器开启了安全浏览功能&#xff0c;下文介绍解决方案。 解决方案 取消华为浏览器设置中的安全浏览功能即可&#xff0c;操作步骤如下。打开…

EtherCAT报文-FPRD(配置地址读)抓包分析

0.工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1.EtherCAT报文帧结构 EtherCAT使用标准的IEEE802.3 Ethernet帧结构&#xff0c;帧类型为0x88A4。EtherCAT数据包括2个字节的数据头和44-1498字节的数据。数据区由一个或…

数据结构-表、树、图

一、表 1.1、散列表 也叫哈希表&#xff0c;把数据分散在列表中&#xff0c;依赖于数组下标访问的特性&#xff0c;数组的一种拓展。 散列思想&#xff1a; 即映射思想&#xff0c;用键值对来保存信息&#xff0c;键&#xff08;key&#xff09;和值&#xff08;value&a…

E117-经典赛题-主机发现与信息收集

任务实施: E117-经典赛题-主机发现与信息收集 任务环境说明&#xff1a; 服务器场景&#xff1a;p9_bt5-1&#xff08;用户名&#xff1a;root&#xff1b;密码&#xff1a;toor&#xff09; 服务器场景操作系统&#xff1a;Back Track five kali Linux 192.168.32.1…

【C++11】

目录 一、列表初始化1.1&#xff5b;&#xff5d;初始化1.2 std::initializer_list 二、声明2.1auto2.2decltype2.3nullptr 三、STL的变化四、右值引用和移动4.1左值引用与右值引用4.2右值引用的场景和意义4.3完美转发4.4完美转发的某个应用场景 四、lambda4.1lambda表达式4.2l…

Zabbix监控系统与部署Zabbix5.0监控(系列操作完整版)

Zabbix监控系统与部署Zabbix5.0监控&#xff08;系列操作完整版&#xff09; 1、监控软件的作用2、Zabbix基本介绍2.1Zabbix是什么&#xff1f;2.2Zabbix监控原理2.3Zabbix的优点2.4Zabbix的缺点2.5Zabbix监控系统的监控对象 3、Zabbix的监控架构3.1server-client架构3.2server…

EtherCAT报文-APRD(自动增量读)抓包分析

0.工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1.EtherCAT报文帧结构 EtherCAT使用标准的IEEE802.3 Ethernet帧结构&#xff0c;帧类型为0x88A4。EtherCAT数据包括2个字节的数据头和44-1498字节的数据。数据区由一个或…

感知机算法

感知机算法 二分类的情况 原理 样本集 X \pmb X X有两个类情况&#xff0c;感知机 Y w X b YwXb YwXb可以将样本集 X \pmb X X分为成功两类 Y w X b { > 0 , x ∈ w 1 < 0 , x ∈ w 2 YwXb \begin{cases}>0 \quad,\quad x \in w_1 \\ <0 \quad,\quad x \i…

Radius OTP完成堡垒机登录认证 安当加密

Radius OTP&#xff08;One-Time Password&#xff09;是一种用于身份验证的协议&#xff0c;它通过向用户发送一个一次性密码来验证用户的身份。使用Radius OTP可以实现堡垒机登录&#xff0c;以下是一些实现步骤&#xff1a; 1、安装Radius服务器 首先需要安装Radius服务器…

Matlab-ODE45:求解状态变量(微分方程组)

ode45函数 ode45实际上是数值分析中数值求解微分方程组的一种方法&#xff0c;4阶五级Runge-Kutta算法。 调用方法 ​ 其实这种方程的每一个状态变量都是t 的函数&#xff0c;我们可以从现代控制理论的状态空间来想。因此返回[ t , x ]&#xff0c;其中t是一个列向量&#xf…

【电源专题】CCM (ContinuousConduction Mode)和DCM(Discontinuous Conduction Mode)有什么区别?

在工作中,查看规格书的时候会看到CCM/DCM等专业词汇。那么什么是CCM?什么是DCM呢? DCM和CCM的概念 回顾文章:【电源专题】什么是开关稳压器的热回路?如何优化热回路?我们可以知道当开关管上管Q1导通Q2关断时,回路为绿色路径,电感储能同时给输出提供能量。当Q1关断Q2导…

【AI】深度学习——循环神经网络

神经元不仅接收其他神经元的信息&#xff0c;也能接收自身的信息。 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一类具有短期记忆能力的神经网络&#xff0c;可以更方便地建模长时间间隔的相关性 常用的参数学习可以为BPTT。当输入序列比较…

图解 RIP

路由器能把全世界的网络连接起来&#xff0c;再根据路由表进行数据转发。路由表项可以手动配置添加&#xff0c;但是面对不计其数、而且动态变化的网络环境&#xff0c;手动添加路由表项显得不切实际&#xff0c;必须使用可以自动生成路由表项、动态感知网络变化的网络协议&…

nginx的location优先级与重定向

概念 1.location是Nginx中的块级指令(block directive),&#xff0c;location指令的功能是用来匹配不同的url请求&#xff0c;进而对请求做不同的处理和响应&#xff0c;这其中较难理解的是多个location的匹配顺序。 2.我们输入的网址叫做请求URI&#xff0c;nginx用请求URI与…

React高级特性之受控和非受控组件

一、受控组件 受控组件&#xff1a;input框自己的状态被React组件状态控制 // 类组件引入React import React from reactclass InputComponent extends React.Component{state {message: zm66666}changeHandler (e) > {this.setState({message: e.target.value})}render…

第五十八章 学习常用技能 - 查看查询缓存

文章目录 第五十八章 学习常用技能 - 查看查询缓存查看查询缓存建立索引使用调谐表工具 第五十八章 学习常用技能 - 查看查询缓存 查看查询缓存 对于 SQL&#xff08;用作嵌入式 SQL 时除外&#xff09;&#xff0c;系统会生成可重用代码来访问数据&#xff0c;并将该代码放置…