【C++11(二)】lambda表达式和可变参数模板

在这里插入图片描述

一、可变参数模板

C++11的新特性可变参数模板
能够让您创建可以接受
可变参数的函数模板和类模板

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}

参数包是不支持下标解析的
在这里插入图片描述

1.1 递归函数方式展开参数包

// 递归终止函数
void ShowList()
{cout << endl;
}// 展开函数
// 增加一个模板参数让编译器自己去解析这个参数包里的东西
template <class T, class ...Args>
void ShowList(const T& value, Args... args)
{cout << value <<" ";ShowList(args...); // 如果是0个参数的参数包就会调用void ShowList()// 如果参数包接收的char类型的参数,会再去调匹配的ShowList函数// 调不到就只能调自己,根据模板推导类型// 打印完,参数包再往下传,0个参数就调用void ShowList()// void ShowList()可以认为是递归终止函数
}int main()
{ShowList(); // 编译器会找最匹配的,调void ShowList()ShowList(1); // 1传给value,后面的参数包就没有了,参数包代表0-n个参数ShowList(1, 'A'); // 1传给value,'A'传给参数包ShowList(1, 'A', std::string("sort"));return 0;
}

二、lambda表达式

C++98中
对一个数据集合中的元素排序
可以使用std::sort

如果待排序元素为自定义类型
需要自己写仿函数
如果每次按自定义类型不同的成员变量
进行排序就要写多个仿函数,十分不方便
因此,C++11语法中的Lambda表达式
便是解决此类问题

lambda表达式

int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price > g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate < g2._evaluate; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate > g2._evaluate; });
}

可以发现lambda表达式是一个匿名函数

1.1 lambda表达式语法

书写格式:
[捕捉列表] (参数列表) mutable ->return-type { 函数体 }

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

用lambda表达式实现add

auto add = [](int x, int y)->int { return x + y; };// cout << [](int x, int y)->int { return x + y; }(1, 2) << endl; // 这样写比较抽象
cout << add(1, 2) << endl;auto add2 = [](int x, int y)
{ return x + y; 
};
cout << add2(3, 2) << endl;[] {}; // 最简单的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 } };// 用lambda对自定义类型比较大小// <auto priceLess = [](const Goods& g1, const Goods& g2)->bool { return g1._price < g2._price; };sort(v.begin(), v.end(), priceLess);// >sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool { return g1._price > g2._price; });// 比较评价sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool {return g1._evaluate > g2._evaluate; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool {return g1._evaluate < g2._evaluate; });return 0;
}

捕捉变量

int main()
{int x = 1, y = 2;auto swap1 = [](int& rx, int& ry){// 只能用当前作用域的变量int tmp = rx;rx = ry;ry = tmp;};swap1(x, y);cout << x << " " << y << endl;// 还可以换一种写法// 想用外面的变量,则可以利用捕捉列表进行捕捉(捕捉过来的对象是外面对象的拷贝)/*// 传值捕捉auto swap2 = [x, y]() mutable // 捕捉多个值用逗号分割即可;直接给值叫做传值捕捉,传值捕捉无法修改,加上mutable(异变)就可以修改{int tmp = x;x = y;y = tmp;};swap2();cout << x << " " << y << endl;*/// mutable用得比较少,建议// 引用捕捉auto swap2 = [&x, &y](){int tmp = x;x = y;y = tmp;};swap2();cout << x << " " << y << endl;// 还可以混合捕捉,x引用捕捉,y传值捕捉// 全部引用捕捉auto func1 = [&](){// ...};// 全部传值捕捉auto func2 = [=](){// ...};// 全部引用捕捉,x传值捕捉auto func3 = [&, x](){// ...};return 0;
}

1.2 函数对象与lambda表达式

函数对象,又称为仿函数
即可像函数一样使用的对象
(在类中重载了operator()运算符的类对象)

class Rate
{
public:Rate(double rate): _rate(rate){}double operator()(double money, int year){ return money * _rate * year;}
private:double _rate;
};
int main()
{
// 函数对象double rate = 0.49;Rate r1(rate);r1(10000, 2);
// lamberauto r2 = [=](double monty, int year)->double{return monty*rate*year; 
};r2(10000, 2);return 0;
}

lambda表达式大小为1个字节
在编译器角度是没有lambda
定义一个lambda
编译器自动生成一个仿函数对象的类型
在该类中重载了operator()
该类是一个空类,空类没给成员变量就是一个字节

函数对象将rate作为其成员变量
在定义对象时给出初始值即可
lambda表达式通过捕获列表可以
直接将该变量捕获到

三、包装器

C++中的function本质是一个类模板
也是一个包装器

int f(int a, int b)
{return a + b;
}struct Functor
{
public:int operator()(int a, int b){return a + b;}
};int main()
{// int(*pf1)(int, int) = f; // 不是常规的指针类型,写法复杂// 假设要求要声明一个统一的类型// map<string, > // 这里要声明可调用类型,f和Functor调用起来都是一样的,但类型不一样,一个是函数指针一个是类// 这时候就没法声明,而包装器就可以统一封装出可调用类型function<int(int, int)> f1 = f; // 返回值加参数包,参数包就是把实际要的类型写上function<int(int, int)> f2 = Functor(); // Function可以对函数指针和仿函数对象进行包装function<int(int, int)> f3 = [](int a, int b) { return a + b; };cout << f1(1, 2) << endl; // 包装以后两个类型的对象是一样的cout << f2(2, 2) << endl;cout << f3(3, 3) << endl;map<string, function<int(int, int)>> opFuncMap; opFuncMap["函数指针"] = f;opFuncMap["仿函数"] = Functor();opFuncMap["lambda"] = [](int a, int b) { return a + b; };// 包装器的作用:更好的控制可调用对象的类型return 0;
}

静态成员和非静态成员的包装

class Plus
{
public:Plus(int rate): _rate(rate){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _rate;}
private:int _rate = 2;
};int main()
{function<int(int, int)> f1 = Plus::plusi; // 包装静态成员函数正常包装就可以// 非静态成员函数,就不能这样直接包装// function<double(double, double)> f2 = Plus::plusd;// error C3867: “Plus::plusd”: 非标准语法;请使用 "&" 来创建指向成员的指针// 普通成员函数名代表函数指针.静态成员也一样,指定类域就可取到这个函数指针// 非静态成员需要加一个&// 非静态传参还有一个this指针需要传参// error C2440 : “初始化”: 无法从“double(__cdecl Plus::*)(double, double)”转换为“std::function<double(double, double)>”function<double(Plus, double, double)> f2 = &Plus::plusd; // 也可以传Plus*,左值能被取地址,右值不行,匿名对象是右值不能取地址,就不能用匿名对象// 传指针也可以,传对象也可以,因为这不是直接去掉用plusd这个函数,我是一个包装器,f1是直接调用Plusi// f2是用对象去掉用Plusd// 当Plusd是指针,就用指针取调用Plusd// 如果是对象就用对象调用Plusd cout << f1(1, 2) << endl;cout << f2(Plus(2), 20, 20) << endl; // 第一个正常调用,第二个需要加一个匿名对象;需要写一个构造函数,也可以不写,Plus就不能传参// 也可以不用匿名对象Plus p1(3);cout << f2(p1, 20, 20) << endl;return 0;
}

bind

调整参数顺序

void Print(int a, int b)
{cout << a << " ";cout << b << endl;
}int main()
{Print(10, 20); // auto RPrint =  bind(Print, placeholders::_2, placeholders::_1); // 第一个参数传可调用对象,_1是一个占位符也是第一个参数,-2是第二个参数以此类推,默认是拿不到的,它放在placeholders命名空间里面function<void(int, int)> RPrint = bind(Print, placeholders::_2, placeholders::_1);// 两种写法都可以推荐用autoRPrint(10, 20);return 0;
}

调整参数个数

class Sub
{
public:Sub(int rate): _rate(rate){}int func(int a, int b){return (a - b) * _rate;}
private:int _rate;
};int main()
{function<int(Sub, int, int)> fSub = &Sub::func;cout << fSub(Sub(3), 10, 20) << endl;function<int(int, int)> fSub1 = bind(&Sub::func, Sub(3), placeholders::_1, placeholders::_2);cout << fSub1(10, 20) << endl;// 把隐藏this指针绑死就只用传两个参数// 把第二个参数绑死function<int(Sub, int)> fSub2 = bind(&Sub::func, placeholders::_1, 100, placeholders::_2);// 第二个参数绑死了,第三个参数是_2,还是按顺序挨着走 cout << fSub2(Sub(3), 20) << endl;}

在这里插入图片描述
本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见

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

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

相关文章

科普文:贝叶斯过滤器判定垃圾邮件

简介 贝叶斯分类的运作是借着使用标记(一般是字词&#xff0c;有时候是其他)与垃圾邮件、非垃圾邮件的关连&#xff0c;然后搭配贝叶斯推断来计算一封邮件为垃圾邮件的可能性。 贝叶斯垃圾邮件过滤是非常有威力的技术&#xff0c;可以修改自己以符合个别使用者的需要&#xff0…

C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码+编号 检测,后续裁剪出图片并摆正显示

C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码编号 检测&#xff0c;后续裁剪出图片并摆正显示 目录 效果 模型信息 项目 代码 下载 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-06-25T10:59:15.206586 description&#xff1a;…

React 19 新特性集合

前言&#xff1a;https://juejin.cn/post/7337207433868197915 新 React 版本信息 伴随 React v19 Beta 的发布&#xff0c;React v18.3 也一并发布。 React v18.3相比最后一个 React v18 的版本 v18.2 &#xff0c;v18.3 添加了一些警告提示&#xff0c;便于尽早发现问题&a…

利用百数应用优化制造细节,提升生产效率的技术实践

制造管理是确保企业高效、高质生产的核心环节&#xff0c;对于提高企业的运营效率、质量控制、成本控制、交货期保障、资源优化、创新能力以及风险管理等方面都具有重要意义&#xff0c;它能帮助企业在激烈的市场竞争中保持领先地位&#xff0c;同时实现资源的有效利用和风险的…

顺序栈与链式栈

目录 1. 栈 1.1 栈的概念 2. 栈的实现 3. 顺序栈的实现 3.1 顺序栈的声明 3.2 顺序栈的初始化 3.3 顺序栈的入栈 3.4 顺序栈的出栈 3.5 顺序栈获取栈顶元素 3.6 顺序栈获取栈内有效数据个数 3.7 顺序栈判断栈是否为空 3.8 顺序栈打印栈内元素 3.9 顺序栈销毁栈 3…

[数据集][目标检测]鸡蛋缺陷检测数据集VOC+YOLO格式2918张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2918 标注数量(xml文件个数)&#xff1a;2918 标注数量(txt文件个数)&#xff1a;2918 标注…

算法金 | 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost 算法大全

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 决策树是一种简单直观的机器学习算法&#xff0c;它广泛应用于分类和回归问题中。它的核心思想是将复杂的决策过程分解成一系列简单的决…

【推荐】Prometheus+Grafana企业级监控预警实战

新鲜出炉&#xff01;&#xff01;&#xff01;PrometheusGrafanaAlertmanager springboot 企业级监控预警实战课程&#xff0c;从0到1快速搭建企业监控预警平台&#xff0c;实现接口调用量统计&#xff0c;接口请求耗时统计…… 详情请戳 https://edu.csdn.net/course/detai…

Word页码设置,封面无页码,目录摘要阿拉伯数字I,II,III页码,正文开始123为页码

一、背景 使用Word写项目书或论文时&#xff0c;需要正确插入页码&#xff0c;比如封面无页码&#xff0c;目录摘要阿拉伯数字I&#xff0c;II&#xff0c;III为页码&#xff0c;正文开始以123为页码&#xff0c;下面介绍具体实施方法。 所用Word版本&#xff1a;2021 二、W…

HTTPS 代理的优点和缺点是什么?

HTTPS&#xff08;超文本安全传输协议&#xff09;作为一种基于HTTP加上SSL安全层的网络通信协议&#xff0c;已经成为互联网上广泛使用的IP协议之一。它在保证信息安全和隐私方面具有很多优势&#xff0c;但也存在一些缺点。接下来&#xff0c;我们就来探究一下HTTPS协议的优缺…

Qt篇——获取Windows系统上插入的串口设备的物理序号

先右键【此电脑-管理- 设备管理器-端口&#xff08;COM和LPT&#xff09;】中找到我们插入的某个设备的物理序号&#xff0c;如下图红色矩形框出的信息&#xff0c;这个就是已插入设备的物理序号&#xff08;就是插在哪个USB口的意思&#xff09;。 在Linux下我们可以通过往/et…

【踩坑】修复循环设置os.environ[‘CUDA_VISIBLE_DEVICES‘]无效

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 问题示例 for gpus in [0, 1, 2, 3, 4, 5, 6, 7]:os.environ[CUDA_VISIBLE_DEVICES] gpusprint(torch.cuda.get_device_name(0)) 始终将使用第…

Mac安装多版本node

Mac下使用n模块去安装多个指定版本的Node.js&#xff0c;并使用命令随时切换。 node中的n模块是&#xff0c;node专门用来管理node版本的模块&#xff0c;可以进行node版本的切换&#xff0c;下载&#xff0c;安装。 1.安装n npm install -g n 2.查看版本 n --version 3.展…

动作捕捉与数字人实训室,引领动漫专业创新发展

如今&#xff0c;随着全身动作捕捉设备在动漫行业中的应用越来越重要&#xff0c;传统的教学模式与市场需求逐渐脱节&#xff0c;原有的教学方式和思路急需进行调整。高校通过搭建动作捕捉与数字人实训室&#xff0c;可以使得教学质量和效率大大提升&#xff0c;让学生能够接触…

如何采集拼多多的商品或店铺数据

怎么使用简数采集器批量采集拼多多的商品或店铺相关信息呢&#xff1f; 简数采集器暂时不支持采集拼多多的商品或店铺相关数据&#xff0c;只能采集页面公开显示的信息&#xff0c;谢谢。 简数采集器采集网站文章资讯等数据特别简单高效&#xff1a;只需输入网站网址&#xf…

全景vr交互微课视频开发让学习变得更加有趣、高效

在数字化教育的浪潮中&#xff0c;3D虚拟微课系统操作平台以其独特的魅力和创新的功能&#xff0c;成为吸引学生目光的焦点。这个平台不仅提供了引人入胜的画面和内容丰富的课件&#xff0c;更通过技术革新和制作方式的探索&#xff0c;将课程制作推向了一个全新的高度。 随着技…

HarmonyOS NEXT Developer Beta1配套相关说明

一、版本概述 2024华为开发者大会&#xff0c;HarmonyOS NEXT终于在万千开发者的期待下从幕后走向台前。 HarmonyOS NEXT采用全新升级的系统架构&#xff0c;贯穿HarmonyOS全场景体验的底层优化&#xff0c;系统更流畅&#xff0c;隐私安全能力更强大&#xff0c;将给您带来更高…

基于Cisco的校园网络拓扑搭建

特此说明&#xff1a;请先看评论区留言哦~ 一、基础配置 1.新建拓扑图 2.服务器配置 3.PC端配置 4.核心交换机配置 a.CORE-S1 Switch>enable Switch#configure terminal Switch(config)#hostname CORE-S1 CORE-S1(config)#vlan 10 CORE-S1(config-vlan)#vlan 20 CO…

【zabbix】zabbix 自动发现与自动注册、proxy代理

1、配置zabbix自动发现&#xff0c;要求发现的主机不低于2台 zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbi…

第1章,物联网模式简介

物联网模式简介 物联网&#xff08;IoT&#xff09;在最近几年获得了巨大的吸引力&#xff0c;该领域在未来几年将呈指数级增长。这一增长将跨越所有主要领域/垂直行业&#xff0c;包括消费者、家庭、制造业、健康、旅游和运输。这本书将为那些想了解基本物联网模式以及如何混…