C++11 lambda函数和包装器

目录

前言

一.lambda的引入

二、lambda函数的使用

1.一般使用

2.引用

三、包装器

1.包装普通对象

2.包装类成员对象

3.bind


前言

        学习过python的同学应该对lambda函数不陌生,这是一个匿名函数,不需要写函数的名字。在不会多地方调用某个简单函数的地方,就可以使用lambda。

一.lambda的引入

        在学习lambda函数之前,我们来看一个用例。这是一些商品,我们需要对商品进行排序。

struct Goods
{
	string _name;  // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, 
		{ "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end());
	sort(v.begin(), v.end());
}

由于商品是自定义类型,比较函数要我们自己写,在Goods类里面写operator>很不方面。

  1. 无法使用sort函数,需要自己写排序,
  2. 排序的方式有很多,比如价格升序和降序,评价的升序和降序。

 因此一般情况下我们都会写仿函数来帮助我们进行比较。例如下面两个仿函数

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

给sort函数传递仿函数就可以按照我们的想法进行排序了。 

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

二、lambda函数的使用

1.一般使用

lambda使用方法如下,有点长,先不用看,直接看后面的例子

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

  • [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来 判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda 函数使用。
  • (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以 连同()一起省略
  • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。 
  • ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  • {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

举个例子,如下,[]为捕捉列表(先不捕捉,后续会讲),(int x)为参数,->int返回类型为int,{}里面存放函数内容

[](int x)->int {cout << x << endl; return 0; };

如下两个方法可以进行lambda函数的调用,

第一个是直接在后面给参数调用。

第二个是赋值给auto 变量,再使用该变量名进行调用。

对于之前商品排序,现在我们也会修改了,一下子就搞定了。

2.引用

方法一:参数传引用,这是我们熟悉的方法,由于不需要返回参数,因此省略->()。如下

 方法二:捕获列表

使用正常捕获,是const的无法修改,需要加mutable变为可修改(见二、1使用方法第三条)。使用引用捕获,不加mutable也可以修改(引用的目的大多是为了修改,这里编译器做了特殊处理)。如下引用捕获了x和y,同时也不需要传参了,因为我们使用了捕获列表,参数列表没有参数。

引用捕获列表还可以使用&,代表引用捕捉当前作用域中的所有变量,如下(这里只有x,y)。

三、包装器

1.包装普通对象

function包装器也叫作适配器。他的主要目的是为了包装可调用对象,主要的可调用对象有函数指针,仿函数,lambda。

为什么要包装可调用对象呢?我们来看看他们的弊端。

函数指针用起来太不方便了,写起来很难受。

仿函数需要在全局定义,不够简洁和美观。

lambda类型是匿名的,一般取不到类型。

如果现在我想像cmd命令一样,输入一个指令,计算机进行相应的操作,这个操作就可以是相关的函数,那么我可以进行如下定义。使用map的operator[]进行相关操作,红色方框的类型应该填什么呢?写函数指针和仿函数很不方便,写lambda类型都没有没办法写。这时就需要包装器上场了。

比如我要进行数字的加减乘除操作,我们可以这样传递第二个参数function<double(double a,double b)>,这样代表包装的可调用对象的类型。那么我们实际传参时,只要类型相同,既可以传递函数指针,又可以传递仿函数,还可以传递lambda匿名对象,这样非常方便。(注意添加头文件#include <functional>)如下所示

2.包装类成员对象

代码如下

class Add
{
public:
	static int addi(int a, int b)
	{
		return a + b;
	}
	double addb(double a, double b)
	{
		return a + b;
	}
};

int main()
{
	function<int(int, int)> f1 = &Add::addi;
	cout << f1(5, 3) << endl;
}

 包装类里面的静态函数,指定类域即可直接包装,&最好填,也可以不填。

如果是非静态呢? 由于类的非静态变量有this指针,因此这里编译不通过。

 我们可以给第一个参数传递类指针,再定义一个类对象,取地址传过去就可以了。

还有一种写法,算是编译器的特殊处理,可以不用再生成类对象。

但是始终这个方法不太好,本来我就只想传两个参数,你一定要让我传第一个一直固定的,不是多此一举嘛,这时bind函数就出场了。

3.bind

bind也是在头文件<functional>里面的,他的作用是绑定函数,让函数参数变成我们想要的个数和顺序

如下,绑定了一个减法lambda函数,第一个参数使用placeholders作用域_2(代表前面那个函数的第二个参数),第二个参数为该作用域下的_1(代表前面那个函数的第一个参数)。相当于10给到了y,3给到了x,因此输出结果是-7。

如果我们给lambda函数第一个参数x为固定值,如下给20,那么我们需要将前面function的参数个数减少一个,同时调用的时候也只需要传一个参数,也就是placeholders::_1(因为只有一个参数)。 

当然第二个参数也可以给固定值。

学会了基本用法,我们回过头来修改类的成员函数。将function只设置两个参数,同时将Add::addb函数的第一个参数固定死传Add(),后续再传placeholders::_1, placeholders::_2,代表实参的第一个和第二个就好。

这样就可以按照我们的想法进行传参了。

谢谢大家观看 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kubeadm来搭建k8s集群。

我们采用了二进制包搭建出的k8s集群&#xff0c;本次我们采用更为简单的kubeadm的方式来搭建k8s集群。 二进制的搭建更适合50台主机以上的大集群&#xff0c;kubeadm更适合中小型企业的集群搭建 主机配置建议&#xff1a;2c 4G 主机节点 IP …

ElementUI的Table组件行合并上手指南

ElementUI的Table组件行合并 &#xff0c;示例用官网vue3版的文档 <el-table :data"tableData" :span-method"objectSpanMethod" border style"width: 100%; margin-top: 20px"><el-table-column prop"id" label"ID&qu…

全面解析 I2C 通信协议

全面解析 I2C 通信协议 lvy 嵌入式学习规划 2023-12-22 21:20 发表于陕西 嵌入式学习规划 嵌入式软件、C语言、ARM、Linux、内核、驱动、操作系统 80篇原创内容 公众号 点击左上方蓝色“嵌入式学习规划”&#xff0c;选择“设为星标” 1、什么是I2C协议 I2C 协议是一个允许…

postman使用-03发送请求

文章目录 请求1.新建请求2.选择请求方式3.填写请求URL4.填写请求参数get请求参数在params中填写&#xff08;填完后在url中会自动显示&#xff09;post请求参数在body中填写&#xff0c;根据接口文档请求头里面的content-type选择body中的数据类型post请求参数为json-选择raw-选…

高压放大器的使用方法是什么

高压放大器是一种重要的电子设备&#xff0c;其主要功能是放大输入信号的电压&#xff0c;并输出更高电压的信号。它在各种工业、实验室和研究领域都有着广泛的应用。下面安泰电子官网将详细介绍高压放大器的使用方法以及相关注意事项。 高压放大器是一种专门用于将低电压信号转…

Unity is running with Administrator privileges, which is not supported

Unity is running with Administrator privileges, which is not supported 如果还是弹出CMD窗口提示输入密码&#xff0c;但无法怎样都无法输入&#xff0c;请关闭窗口&#xff0c;然后右键快捷方式管理员运行一次。 ----------分割线---------- 为什么这样做&#xff1f; 很…

模型量化 | Pytorch的模型量化基础

官方网站&#xff1a;Quantization — PyTorch 2.1 documentation Practical Quantization in PyTorch | PyTorch 量化简介 量化是指执行计算和存储的技术 位宽低于浮点精度的张量。量化模型 在张量上执行部分或全部操作&#xff0c;精度降低&#xff0c;而不是 全精度&#xf…

多线程编程(二)信号量

上边的函数是获取资源&#xff0c;下边的函数是释放资源。信号量就是当有多个线程争夺共享资源的时候信号量相当于管控的&#xff0c;57个人去50个位置的餐厅吃饭&#xff0c;信号量是管理开关门的呢个。 QSemaphore freesapce(buffersize);//缓冲区大小。 QSemaphore usedsp…

Oracle数据updater如何回滚

1.查询update语句执行的时间节点 &#xff1b; select t.FIRST_LOAD_TIME, t.SQL_TEXT from v$sqlarea t where to_char(t.FIRST_LOAD_TIME) > 2023-03-19/17:00:00 order by t.FIRST_LOAD_TIME desc;开启表的行迁移 alter table test enable row movement;3.回滚表数据到…

uni-app/vue封装etc车牌照输入,获取键盘按键键值

先看下效果如下&#xff1a; 动态图如下 uniapp的keyup获取不到keyCode和compositionstart&#xff0c;compositionend&#xff0c;所以需要监听input节点的keyup事件&#xff0c; 思路以及代码如下&#xff1a; 1.将每一个字符用文本框输入&#xff0c;代码如下 <view …

volatile关键字的作用是什么?

大家好&#xff0c;我是"java继父"伯约&#xff0c;这篇对大家有帮助的话求一个赞&#xff0c;另外文章末尾放了我从月入7k到现在3W的学习资料&#xff0c;大家可以去领一下&#xff08;无偿&#xff09;。 1.防重排序 我们从一个最经典的例子来分析重排序问题。大家…

[python]python使用M-LSD直线检测算法onnx部署模型实时检测

介绍 github地址&#xff1a;https://github.com/navervision/mlsd LSD (M-LSD)一种用于资源受限环境的实时轻量线段检测器。它利用了极其高效的 LSD 架构和新颖的训练方案&#xff0c;包括 SoL 增强和几何学习方案。模型可以在GPU、CPU甚至移动设备上实时运行。算法已开源&a…

云原生机器学习平台cube-studio开源项目及代码简要介绍

1. cube-studio介绍 云原生机器学习平台cube-studio介绍&#xff1a;https://juejin.cn/column/7084516480871563272 cube-studio是开源的云原生机器学习平台&#xff0c;目前包含特征平台&#xff0c;支持在/离线特征&#xff1b;数据源管理&#xff0c;支持结构数据和媒体标…

maven工具的搭建以及使用

文章目录 &#x1f412;个人主页&#x1f3c5;JavaEE系列专栏&#x1f4d6;前言&#xff1a;&#x1f380;首先进行maven工具的搭建&#x1f993;1.[打开下载 maven 服务器官网](http://maven.apache.org)&#x1fa85;2.解压之后&#xff0c;配置环境变量&#x1f3e8;3.打开设…

EasyExcel导出

1.简介 官网&#xff1a;EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 2.案例 2.1 实现的效果 效果图如下&#xff1a; 2.2 实现步骤 三种情景&#xff0c;主要是表头和数据有区别&#xff0c;简列实现步骤如下&#xff1a; 2.3 具体实现 2.3.1 前置-依赖导入…

双向链表基本操作及顺序和链表总结

目录 基本函数实现 链表声明 总的函数实现声明 创建一个节点 初始化链表 打印 尾插 尾删 头插 头删 查找 pos前插入 删除pos位置 销毁链表 顺序表和链表总结 基本函数实现 链表声明 typedef int DLTDataType;typedef struct DListNode {struct DListNode* nex…

小白必学!手把手教你从零打造Facebook脸书商城

Facebook 脸书商城已经逐渐成为了跨境电商开拓市场的选择&#xff0c;这是因为脸书商城背靠 Facebook 巨大的平台流量&#xff0c;可以链接卖家的品牌&#xff0c;增加品牌曝光率&#xff0c;提高流量&#xff0c;是一个非常好的流量洼地。如果你还没有注册脸书商城&#xff0c…

图像处理-周期噪声

周期噪声 对于具有周期性的噪声被称为周期噪声&#xff0c;其中周期噪声在频率域会出现关于中心对称的性质&#xff0c;如下图所示 带阻滤波器 为了消除周期性噪声&#xff0c;由此设计了几种常见的滤波器&#xff0c;其中 W W W表示带阻滤波器的带宽 理想带阻滤波器 H ( u …

【Fastadmin】通用排序weigh不执行model模型的事件

在model模型类支持的before_delete、after_delete、before_write、after_write、before_update、after_update、before_insert、after_insert事件行为中&#xff0c;我们可以快捷的做很多操作&#xff0c;如删除缓存、逻辑判断等 但是在fastadmin的通用排序weigh拖动中无法触发…

Flink项目实战篇 基于Flink的城市交通监控平台(上)

系列文章目录 Flink项目实战篇 基于Flink的城市交通监控平台&#xff08;上&#xff09; Flink项目实战篇 基于Flink的城市交通监控平台&#xff08;下&#xff09; 文章目录 系列文章目录1. 项目整体介绍1.1 项目架构1.2 项目数据流1.3 项目主要模块 2. 项目数据字典2.1 卡口…