C++11 lambda函数和包装器

news2025/1/20 21:52:02

目录

前言

一.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,代表实参的第一个和第二个就好。

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

谢谢大家观看 

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

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

相关文章

C# vs报错 id为XX的进程当前未运行

报错原因&#xff1a;虚拟目录端口被占用 解决方法&#xff1a;重新配置新的目录端口就行 1、选择项目属性 2、更改端口号&#xff0c;点击创建虚拟目录 3、重新生成项目

C# WPF上位机开发(MVVM模式开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学习过vue的同学都知道mvvm这个名词。从字面上理解&#xff0c;可能有点拗口&#xff0c;但是我们可以去理解一下它的优点是什么。mvc相信大家都明…

InDesign插件-常规功能开发-添加参考线-js脚本开发-ID插件

文章目录 1.脚本执行概述2.InDesign 对象模型3.源码解析4.界面及结果5.总结 1.脚本执行概述 “脚本”面板和“脚本标签”面板概述&#xff0c;InDesign 包含两个用于脚本的面板&#xff1a;“脚本”面板和“脚本标签”面板。在“脚本”面板中可以运行脚本而不必离开 InDesign。…

Python sanic框架钉钉和第三方打卡机实现

同样还是需要开通钉钉应用这里就不错多说了 第一步:梳理逻辑流程 前提&#xff1a;打卡的机器是使用postgres数据库&#xff0c;由于因为某些原因&#xff0c;钉钉userId 我已经提前获取到了存放到数据库里。 1.用户打卡成功后&#xff0c;我们应该监听数据库进行查询&#xf…

【教学类-35-07】17号的字帖(三)年份字帖“2023”(A4竖版1份)

作品展示 前四行是一个数字的描写 后四行是合并的年份4个数字 背景需求&#xff1a; 大4班17号孩子练习数字书写&#xff0c;上一次是“17”号和大“4”&#xff0c;第3份就是年份 【教学类-35-05】17号的学号字帖&#xff08;A4竖版1份&#xff09;-CSDN博客文章浏览阅读4…

数据结构--查找

目录 1. 查找的基本概念 2. 线性表的查找 3. 树表的查找 3.1 二叉排序树 3.1.1 定义: 3.1.2 存储结构&#xff1a; 3.1.3 二叉排序树的查找 3.1.4 二叉排序树的插入 3.1.5 二叉排序树删除 3.2 平衡二叉树&#xff08;AVL 3.2.1 为什么要有平衡二叉树 3.2.2 定义 3.3 B-树 3.3.1…

Flink1.17实战教程(第五篇:状态管理)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…

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

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

信息网络协议基础-IPv6协议

文章目录 概述为什么引入IP服务模型IPv4的可扩展性问题解决方法***CIDR(Classless Inter-Domain Routing, 无类别域间寻路)前缀汇聚***前缀最长匹配***NAT(网络地址转换)存在的问题解决方案路由表配置***局限性IPv6协议头标IPv6地址表示前缀类型单播地址链路局部地址(Link-Loca…

RabbitMq知识概述

本文来说下RabbitMq相关的知识与概念 文章目录 概述AMQP协议Exchange 消息如何保证100&#xff05;投递什么是生产端的可靠性投递可靠性投递保障方案 消息幂等性高并发的情况下如何避免消息重复消费confirm 确认消息、Return返回消息如何实现confirm确认消息return消息机制 消费…

构建高效数据中台:集群规划与搭建的最佳实践指南

架构设计 Rack(机架)配置建议 大数据集群规划 安装细节见配套文档 两地三中心 两地三中心是一种信息技术架构模式,通常用于灾难恢复和业务连续性计划。这种模式设计有两个物理位置(两地),在这两个位置上部署了三个数据中心(三中心):一个主数据中心和两个备份数据中心…

电子邮件过滤软件SpamSieve mac高级功能

SpamSieve mac是一款电子邮件过滤软件&#xff0c;旨在帮助用户有效地识别和阻止垃圾邮件。该软件可通过机器学习算法自动学习您的邮箱中哪些邮件是垃圾邮件&#xff0c;哪些是正常邮件&#xff0c;并根据您的反馈不断优化过滤效果。 使用SpamSieve非常简单&#xff0c;只需将其…

How to Develop Word Embeddings in Python with Gensim

https://machinelearningmastery.com/develop-word-embeddings-python-gensim/ 本教程分为 6 个部分;他们是&#xff1a; 词嵌入 Gensim 库 开发 Word2Vec 嵌入 可视化单词嵌入 加载 Google 的 Word2Vec 嵌入 加载斯坦福大学的 GloVe 嵌入 词嵌入 单词嵌入是一种提供单词的…

HTML的学习记录

<br /> 标签在 HTML 页面中创换行符。 <hr /> 标签在 HTML 页面中创建水平线。 段落是通过 <p> 标签定义的。 浏览器会自动地在段落的前后添加空行。&#xff08;<p> 是块级元素&#xff09; 文本格式 <b>This text is bold</b>字体加粗 …

腾讯云轻量应用服务器购买流程(两种方式)

腾讯云轻量应用服务器购买指南&#xff0c;有两个入口&#xff0c;一个是在特价活动上购买&#xff0c;一个是在轻量应用服务器官方页面购买&#xff0c;特价活动上购买价格更便宜&#xff0c;轻量2核2G3M带宽服务器62元一年起&#xff0c;阿腾云atengyun.com分享腾讯云轻量应用…

VS配置PCO相机SDK环境

VS配置PCO相机SDK环境 概述:最近要用到一款PCO相机,需要协调其他部件实现一些独特的功能。因此需要用到PCO相机的SDK,并正确配置环境。良好的环境是成功的一半。其SDK可以在官网下载,选择对应版本的安装即可。这里用的是pco.cpp.1.2.0 Windows,VS 2022 专业版。 链接: P…

阿里云 ACK 云上大规模 Kubernetes 集群高可靠性保障实战

作者&#xff1a;贤维 马建波 古九 五花 刘佳旭 引言 2023 年 7 月&#xff0c;阿里云容器服务 ACK 成为首批通过中国信通院“云服务稳定运行能力-容器集群稳定性”评估的产品&#xff0c; 并荣获“先进级”认证。随着 ACK 在生产环境中的采用率越来越高&#xff0c;稳定性保…

【python 的各种模块】(8) 在python使用matplotlib和wordcloud库来画wordcloud词云图

目录 目标&#xff1a;用python画出&#xff0c;网上流行的wordcloud词云图 1 准备工作 1.1环境准备 1.1.1安装步骤 1.2 资源准备 1.2.1 文本文件内容如下 1.2.2 图片资源 2 代码测试 2.1 第一版代码和效果 2.1.1 代码和效果 2.1.2 一般plt里解决中文乱码问题 2.1…

StackOverflowError的JVM处理方式

背景&#xff1a; 事情来源于生产的一个异常日志 Caused by: java.lang.StackOverflowError: null at java.util.stream.Collectors.lambda$groupingBy$45(Collectors.java:908) at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) at java.util.ArrayL…

基于飞浆OCR的文本框box及坐标中心点检测JSON格式保存文本

OCR的文本框box及JSON数据保存 需求说明 一、借助飞浆框出OCR识别的文本框 二、以圆圈形式标出每个框的中心点位置 三、以JSON及文本格式保存OCR识别的文本 四、以文本格式保存必要的文本信息 解决方法 一、文本的坐标来自飞浆的COR识别 二、借助paddleocr的draw_ocr画出…