【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;}
本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见
相关文章:

【C++11(二)】lambda表达式和可变参数模板
一、可变参数模板 C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板 // Args是一个模板参数包,args是一个函数形参参数包 // 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。 template <class ...Arg…...

昇思25天学习打卡营第2天|张量Tensor
张量Tensor 创建张量张量的属性张量索引张量运算 稀疏张量 总结 简单讲讲张量,数学和物理学界以一种方式定义张量,机器学习上则是以另一种方式定义张量,这里的张量也与神经网络联系紧密,神经网络需要进行大量的数学计算࿰…...

[leetcode]valid-triangle-number. 有效三角形的个数
. - 力扣(LeetCode) class Solution { public:int triangleNumber(vector<int>& nums) {int n nums.size();sort(nums.begin(), nums.end());int ans 0;for (int i 0; i < n; i) {for (int j i 1; j < n; j) {int left j 1, righ…...
java SQL server 多实例的情况
而对于java,对付多个数据库实例就有些要注意的了: 首先,同样连接字符串上加上“\实例名”: jdbc:sqlserver://127.0.0.1\\mssqlserver2008;DatabaseNameLPT; 此处应去掉端口1433。因为连接数据库自命名实例的url中没有端口号1433…...

html--404页面
<!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"> <title>404 错误页面不存在&…...

[word] Word如何删除所有的空行? #职场发展#学习方法
Word如何删除所有的空行? 很多网友从网页复制文字粘贴到word文档后发现段落之间有空行,如果文字不多,手动删除这些空行也没有多少工作量,但是如果文字的字数达到成千上万,一个个手动删除这些空行还是很繁琐的。那么&a…...
【CSS】深入探讨 CSS 的 `calc()` 函数
深入探讨 CSS 的 calc() 函数 calc() 是一个 CSS 函数,用于在样式表中进行数学计算,从而动态地设置 CSS 属性值。它允许开发者在指定长度、百分比、数值等时,进行加减乘除运算。通过 calc() 函数,我们可以实现更灵活和响应式的设…...
MongoDB异地备份数据文件脚本(带日志打印,便于排查)
此脚本是以文件夹的形式备份,非压缩包形式 如需备份成加密压缩包,可用此脚本:MongoDB定时异地备份所有数据库为加密压缩包-CSDN博客 1.可以直接下载本文件使用,将其放到mongo安装目录的bin目录下(可手动执行…...

论文导读 | Manufacturing Service Operations Management近期文章精选
编者按 在本系列文章中,我们梳理了顶刊Manufacturing & Service Operations Management5月份发布有关OR/OM以及相关应用的文章之基本信息,旨在帮助读者快速洞察行业/学界最新动态。 推荐文章1 ● 题目:Robust Drone Delivery with Weath…...
【Linux命令】top linux下的任务管理器
一、概述 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态。如果在前台执行该命令,它将独占前台&#…...
2024年在分数限制下,选好专业还是选好学校?
分数限制下,选好专业还是选好学校? 24年高考帷幕落下,一场新的思考与选择悄然来临。对于每一位高考考生,学校和专业都是开启大学新生活的两个前置必选项。但有时候“鱼与熊掌不可兼得”,在分数受限的条件下࿰…...

cropperjs 裁剪/框选图片
1.效果 2.使用组件 <!-- 父级 --><Cropper ref"cropperRef" :imgUrl"url" searchImg"searchImg"></Cropper>3.封装组件 <template><el-dialog :title"title" :visible.sync"dialogVisible" wi…...
ArkTS开发系列之事件(2.8.2手势事件)
上篇回顾:ArkTS开发系列之事件(2.8.1触屏、键鼠、焦点事件) 本篇内容:ArkTS开发系列之事件(2.8.2手势事件) 一、绑定手势方法 1. 常规手势绑定方法 Text(手势).fontSize(44).gesture(TapGesture().onAct…...

【MATLAB源码-第135期】基于matlab的变色龙群优化算法CSA)机器人栅格路径规划,输出做短路径图和适应度曲线。
操作环境: MATLAB 2022a 1、算法描述 变色龙群优化算法(Chameleon Swarm Algorithm,CSA)是一种新颖的群体智能优化算法,受到自然界中变色龙捕食和社交行为的启发。变色龙以其独特的适应能力而著称,能够根…...
使用Python实现深度学习模型:语言模型与文本生成
语言模型是自然语言处理中的核心任务之一,它们用于预测文本中的下一个单词或生成与输入文本相关的新文本。本文将详细介绍如何使用Python实现一个语言模型,并通过这个模型进行文本生成。 我们将使用TensorFlow和Hugging Face的Transformers库来实现这一任务。 1. 语言模型简…...
大数据面试题之Hive(3)
目录 Hive的函数:UDF、UDAF、UDTF的区别? UDF是怎么在Hive里执行的 row_number,rank,dense_rank的区别 Hive count(distinct)有几个reduce,海量数据会有什么问题 HQL:行转列、列转行 一条HQL从代码到执行的过程 了解Hive S…...
华为OD机考题HJ17 坐标移动
前言 应广大同学要求,开始以OD机考题作为练习题,看看算法和数据结构掌握情况。有需要练习的可以关注下。 描述 开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从&am…...
redis修改密码
在Redis中,修改密码通常涉及编辑Redis配置文件或者在运行时通过Redis命令动态修改。 温馨提示:(运行时直接参考第2条) 1.编辑配置文件: 找到Redis配置文件redis.conf,通常位于/etc/redis/或/usr/local/e…...
《昇思 25 天学习打卡营第 7 天 | 模型训练 》
《昇思 25 天学习打卡营第 7 天 | 模型训练 》 活动地址:https://xihe.mindspore.cn/events/mindspore-training-camp 签名:Sam9029 模型训练 本章节-结合前几张的内容所讲-算是一节综合实践 mindscope 框架使用张量 数据类型数据集下载与加载网络构建函…...
HTML/CSS 基础
1、<input type"checkbox" checked> checked 默认选中为复选框 2、表格中的标题<caption> 3、文字标签直接加 title 4、<dl>为自定义列表的整体,包裹<dt><dd> <dt>自定义列表的主题 <dd>主题的每一项内容 5、…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...