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

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

谢谢大家观看 

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

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

相关文章

【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代

目录 前言 机器视觉 缺陷检测 工业上常见缺陷检测方法 内容简介 作者简介 目录 读者对象 如何阅读本书 获取方式 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站 机器视觉…

裁员+失恋或许不能比这更遭了,敬小明一塌糊涂与充满感动的2023,也敬曾经的挚爱与寒冬的冰霜

~ 随机抽取评论区的 3位 小伙伴送上精美礼品 ~ 参与方式&#xff1a;关注、点赞、收藏&#xff0c;评论 "2024&#xff0c;一天当做两天卷&#xff01;" 活动时间&#xff1a;截止到 2024-01-21 00:00:00 礼品清单&#xff1a;CSDN活动周边、自选图书 本文目录 序 …

go语言,ent库与gorm库,插入一条null值的time数据

情景介绍 使用go语言&#xff0c;我需要保存xxxTime的字段至数据库中&#xff0c;这个字段可能为空&#xff0c;也可能是一段时间。我采取的是统一先赋值为空&#xff0c;若有需要&#xff0c;则再进行插入&#xff08;需要根据另一个字段判断是否插入&#xff09; 在我的数据…

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…

IDEA 开发中常用的快捷键

目录 Ctrl 的快捷键 Alt 的快捷键 Shift 的快捷键 Ctrl Alt 的快捷键 Ctrl Shift 的快捷键 其他的快捷键 Ctrl 的快捷键 Ctrl F 在当前文件进行文本查找 &#xff08;必备&#xff09; Ctrl R 在当前文件进行文本替换 &#xff08;必备&#xff09; Ctrl Z 撤…

MySql 中的锁详解 —— 共享锁、排他锁、全局锁、表级锁、页级锁、行级锁、意向锁、记录锁、间隙锁等

目录 一. 前言 二. 锁的分类 三. 共享锁&#xff08;读锁&#xff09;和排他锁&#xff08;写锁&#xff09; 3.1. 共享锁&#xff08;Shared Lock&#xff09; 3.2. 排他锁&#xff08;Exclusive Lock&#xff09; 四. 全局锁、表级锁、页级锁和行级锁 4.1. 全局锁 4.…

Vue axios Post请求 403 解决之道

前言&#xff1a; 刚开始请求的时候报 CORS 错误&#xff0c;通过前端项目配置后算是解决了&#xff0c;然后&#xff0c;又开始了新的报错 403 ERR_BAD_REQUEST。但是 GET 请求是正常的。 后端的 Controller 接口代码如下&#xff1a; PostMapping(value "/login2&qu…

JVM GC 算法原理概述

对于JVM的垃圾收集&#xff08;GC&#xff09;&#xff0c;这是一个作为Java开发者必须了解的内容&#xff0c;那么&#xff0c;我们需要去了解哪些内容呢&#xff0c;其实&#xff0c;GC主要是解决下面的三个问题&#xff1a; 哪些内存需要回收&#xff1f; 什么时候回收&…

【1】Docker详解与部署微服务实战

Docker 详解 Docker 简介 Docker 是一个开源的容器化平台&#xff0c;可以帮助开发者将应用程序和其依赖的环境打包成一个可移植、可部署的容器。Docker 的主要目标是通过容器化技术实现应用程序的快速部署、可移植性和可扩展性&#xff0c;从而简化应用程序的开发、测试和部…

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…

VS配置PCO相机SDK环境

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

【TensorFlow 精简版】TensorFlow Lite

目录 一 TensorFlow Lite简介 二 开发 三 开始使用 一 TensorFlow Lite简介 TensorFlow Lite 是一组工具&#xff0c;可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型&#xff0c;以便实现设备端机器学习。 针对设备端的机器学习进行的优化&#xff1a; ① 延时&…

oracle下载

前言&#xff1a; 官网上提供都是最新的什么19c 21c这些版本&#xff0c;我要的是 11g 12c 或者更老的 8i 9i 这些版本。 准备下载一个oracle12c 版本&#xff0c;但是找了很久&#xff0c;最终…详情请看下面 oracle 数据库版本介绍 Oracle数据库有多个长期支持版本&#x…

格密码基础:子格,q-ary垂直格与线性代数

目录 一.写在前面 二.子空间垂直 2.1 理论解释 2.2 举例分析 三. 零空间 3.1 零空间与q-ary垂直格 3.2 零空间与行/列空间 四. 格密码相关 一.写在前面 格密码中的很多基础原语都来自于线性代数的基本概念&#xff0c;比如举几个例子&#xff1a; 格密码中的非满秩格…

2022年全球软件质量效能大会(QECon上海站)-核心PPT资料下载

一、峰会简介 近年来&#xff0c;以云计算、移动互联网、物联网、工业互联网、人工智能、大数据及区块链等新一代信息技术构建的智能化应用和产品出现爆发式增长&#xff0c;突破了对于软件形态的传统认知&#xff0c;正以各种展现方式诠释着对新型智能软件的定义。这也使得对…

❀My小学习之排序算法❀

目录 排序算法&#xff08;Sorting algorithm&#xff09;:) 一、定义 二、分类 三、评价标准 排序算法&#xff08;Sorting algorithm&#xff09;:) 一、定义 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的…

docker学习(十九、network使用示例bridge)

文章目录 一、容器网络分配情况1.启动容器2.查看容器的network3.容器网络分配 二、bridge1.bridge详细介绍2.实践bridge两两匹配3.创建network&#xff0c;默认bridge network相关内容&#xff1a; docker学习&#xff08;十八、network介绍&#xff09; docker学习&#xff08…

一.windows2012搭建fpt服务器和常见端口介绍

一.windows2012搭建fpt服务器和常见端口介绍 1.打开防火墙2.创建组2.1打开计算机管理2.2创建组并且设置名称和描述 3.创建用户3.1设置用户密码和名称3.2把用户归属于组3.3把user删除掉3.4点击添加然后点高级3.5点击立即查找选择之前设定的组 4.安装ftp服务器4.1点击添加角色和功…

仓储革新:AR技术引领物流进入智慧时代

根据《2022年中国物流行业研究&#xff1a;深度探析行业现状&#xff08;智能设备及智能软件&#xff09;》&#xff0c;报告中提及&#xff1a;“中国社会物流总额依然保持着较为良好的增长态势&#xff0c;年增速已恢复至常年平均水平。2021年社会物流总额细分中工业物流总额…

千巡翼X4轻型无人机 赋能智慧矿山

千巡翼X4轻型无人机 赋能智慧矿山 传统的矿山测绘需要大量测绘员通过采用手持RTK、全站仪对被测区域进行外业工作&#xff0c;再通过方格网法、三角网法、断面法等进行计算&#xff0c;需要耗费大量人力和时间。随着无人机航测技术的不断发展&#xff0c;利用无人机作业可以大…