c++11(三)

news2024/11/28 20:34:35

一、可变参数

1、可变参数模板

c语言中的 scanf 和 printf 可以支持我们传入任意个数的参数,原理就是用了参数包。

//可变参数包
template<class ...Args>
void Print(Args... args)
{}

Args:模板参数包

args:函数形参参数包

声明一个参数包:Args... args  

Args... 表示有0~n个类型,args 表示模板参数定义的形参参数包。

sizeof...(args):求参数包中参数个数

2、参数包在编译时的参数推导递归(方法一)

//最后参数包个数是0时打印换行
void _Printf()
{
	cout << endl;
}

//子函数递归调用 把参数包中的值全部打印
template<class T, class ...Args>
void _Printf(T& t, Args... args)
{
	cout << t << endl;
	_Printf(args...);
}

//主函数调用子函数传入参数包
template<class ...Args>
void Printf(Args... args)
{
	_Printf(args...);
}

int main()
{
	Printf(1, 2.2, "string");
	return 0;
}

结果:

3、运用数组初始化展开参数包(方法二)

template<class T>
int Printf(T t)
{
	cout << t << endl;
	return 0;
}


template<class ...Args>
void showList(Args... args)
{
	//定义数组是为了在构造时展开参数包
	int a[] = { Printf(args)... };//函数Printf推导参数包个数
	cout << endl;
}

int main()
{
	showList(1, "hello", 'x');
	return 0;
}

a 数组创建时,会根据 { } 中的参数进行初始化,可以在此直接将可变参数包展开,展开过程中就完成了参数的解析工作。

结果:

4、emplace系列函数

在stl容器中插入数据可以使用emplace系列函数,这样在多数情况下效率最高。

可以看到用的就是参数包形式的传参,在模板中 Args&&... args 是万能引用。

下面我们对比push_back和emplace_back来讨论emplace系列函数的优势

int main()
{
	std::list<bit::string> l;

	bit::string str1 = "Hello";
	bit::string str2 = "Hello";

	// 插入左值
	l.push_back(str1);
	l.emplace_back(str2);
	cout << endl;

	// 插入 move 出来的右值
	l.push_back(move(str1));
	l.emplace_back(move(str2));
	cout << endl;

	return 0;
}

结论1:参数是左值和move得到的右值,两者并无区别。

int main()
{
	// 插入纯右值
	l.push_back("World");
	l.emplace_back("World");

	return 0;
}

emplace_back函数直接都没有移动构造,emplace 系列函数可以直接将纯右值作为参数传递,传递途中不展开参数包,直到构造函数才把参数包展开,体现可变参数包 的优势(直接传递参数)

结论2:在插入纯右值,并且构造函数能正常接收时,emplace 系列函数可以直接构造,省去了调用移动构造函数时的开销。

总结

1、对于深拷贝的类型,push_back是构造 + 移动构造,emplace_back是直接构造

2、对于浅拷贝的类型,push_back是构造 + 拷贝构造,emplace_back是直接构造

3、由于push_back函数参数写死,所以只能先构造再拷贝构造,但是emplace_back函数参数是参数包,能够随函数一层一层传递下去,到构造函数时一起构造,省去中间所有构造。

4、在插入单参数,左值,move 之后的右值时两者没有区别,当插入多参数时 emplace 参数包就会随函数调用一层一层向下传,最后直接构造。

类别说明
emplace或push / insert 右值对象构造 + 移动构造
emplace参数包构造
emplace或push / insert 左值对象构造 + 拷贝构造
emplace参数包构造
int main()
{
    list<string> l;                 
    string s("111");                //构造
    l.emplace_back(s);              //左值深拷贝
    l.emplace_back(move(s));        //右值移动构造
    l.emplace_back("111");          //单参数参数包最后直接构造
    l.emplace_back(string("111"));  //构造 + 移动构造
}

二、包装器

1、作用

首先我们先了解可调用对象

可调用对象缺点
函数指针类型定义复杂
仿函数对象要定义一个类
lambda没有类型概念

C++中的 function 本质是一个类模板,也是一个包装器。为了函数调用方便,统一可调用对象的调用方式,function包装器用来包装对象,由于底层使用的是operator()函数重载,所以调用方式就能得到统一。

Ret:返回值类型

Args:参数包

2、使用包装器

(1)定义包装器

​#include<functional>
function<返回类型(参数包类型)> fc;

(2)举例

​int f(int a, int b)
{
	return a + b;
}

struct add
{
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};

int main()
{
    //函数指针包装
	function<int(int, int)> fc1 = f;
	//仿函数对象包装
    function<int(int, int)> fc2 = add();
	//lambda表达式包装
    function<int(int, int)> fc3 = [](int a, int b) {return a + b; };
	return 0;
}

注意:包装器只是包装可调用对象,不是定义可调用对象。

3、理解代码

map<string, functional<int(int, int)> func = opFuncMap = {
{" + ", [](int a, int b){return a + b;}},
{" - ", [](int a, int b){return a - b;}},
{" * ", [](int a, int b){return a * b;}},
{" / ", [](int a, int b){return a / b;}},
};

这是命令与动作的对应实现代码,用到了 initializer_list 初始化4个命令与动作的对应操作。

通过包装器封装的函数最后调用函数的代码就会统一,简单。

function<int(int, int)> func = opFuncMap["+"];
func(1, 2);

4、如何包装静态 / 普通成员函数

class Func
{
public:
    static int plusi(int a, int b) {return a + b; };
    
    int plusd(double a, double b) {return a + b; };
}


int main()
{
    //包装静态成员函数
    function<int(int, int)> f1 = &Func::plusi;
    
    //包装普通成员函数(用对象指针)
    function<double(Func*, double, double)> f2 = &Func::plusd;
    Func f;
    f2(&f, 3.1, 2.1);

    //包装普通成员函数(用对象)
    function<double(Func, double, double)> f3 = &Func::plusd;
    f3(Func(), 3.1, 2.1);
}

(1)获取成员函数函数指针方法:&类型 : : 函数名

(2)普通成员函数参数要包含 this 指针,所以对于普通成员函数的 function 定义就一定要带上 this 指针的参数个数(静态函数因为没有 this 指针不用考虑),这时就有两种方法,一种是定义对象指针,一种是定义对象。

问题:要传的参数是对象的指针,为什么第二种用对象传也可以?

首先 this 指针不能显示传递,所以其实 function 底层就是operator() 用传入的对象调用函数,所以在底层就不关心是不是对象的指针,只关心是不是传对象。

三、绑定

1、作用

调整可调用对象的参数个数或参数顺序。

bind 是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象,生成一个新的可调用对象来 “适应” 原对象的参数列表

第二个模板中的 Ret 如果需要修改原来函数对象的返回值,就可以显示实例化来确定特殊的返回类型。

万能引用里面的参数包包括了绑定值和参数(placeholders::_1, placeholders::_2,....)

其中 placeholders::_1 表示传进函数的第一个实参,以此类推。

2、作用一:调整参数顺序

int Sub(int a, int b)
{
	return a - b;
}


int main()
{
	auto f1 = Sub;
	cout << f1(10, 5) << endl;

	 //调整顺序
	auto f2 = bind(Sub, placeholders::_2, placeholders::_1);
	cout << f2(10, 5) << endl;
    return 0;
}

结果:

原理图:

绑定函数时交换实参的位置就能交换参数。

3、作用二:调整参数个数

原理:绑死几个参数到bind函数里面,调用时参数减少。

class Sub
{
public:
	Sub(int x)
		:_x(x)
	{}
	int sub(int a, int b)
	{
		return a - b;
	}
private:
	int _x;
};

int main()
{
    auto f3 = bind(&Sub::sub, placeholders::_1, placeholders::_2, placeholders::_3);
    
    cout << f3(Sub(1), 10, 5) << endl;

    Sub sub(1);
    cout << f3(&sub, 10, 5) << endl;

    // 绑定,调整参数个数
    auto f4 = bind(&Sub::sub, Sub(1), placeholders::_1, placeholders::_2);
    cout << f4(10, 5) << endl;

    auto f5 = bind(&Sub::sub, &sub, placeholders::_1, placeholders::_2);
    cout << f5(10, 5) << endl;

    return 0;
}

上面的代码绑定了调用成员函数所用到的对象,这样每次调用函数就不用传对象。

结果:

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

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

相关文章

检查linux系统中异常进程

1、查看非root运行的进程 [rootbastion-IDC ~]# ps -U root -u root -N 2、查看root运行的进程 [rootbastion-IDC ~]# ps -u root 注意&#xff1a;UID为0的进程&#xff0c;查看该进程所打开的端口和文件 [rootbastion-IDC ~]#ps -ef 查看进程 [rootbastion-IDC ~]# l…

Lesson 77 Terrible toothache

Lesson 77 Terrible toothache 词汇 appointment n. 预约 构成&#xff1a;point v. 指&#xff0c;指向 用法&#xff1a;point to 人 / 物    指着&#xff0c;指向……    point out 指出&#xff08;问题&#xff09; 相关&#xff1a;game point 局点    matc…

statsmodels学习笔记

statsmodels学习笔记 统计模型、假设检验和数据探索。statsmodels是一个python模块&#xff0c;提供了用于估计许多不同统计模型的类和函数&#xff0c;以及用于统计测试和统计数据探索。每个估计器都有一个广泛的结果统计列表。根据现有的统计软件包对结果进行测试&#xff0c…

【C++】深入解析C/C++内存管理:new与delete的使用及原理

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类 本章将分享C为何放弃malloc/free系列&#xff0c;选择新系列new/delete去管理内存。深度探索new/delete的使用及其原理,m…

VBA注释 (<*> + <*>)

在VBA&#xff08;Visual Basic for Applications&#xff09;中&#xff0c;注释是一种用于向代码中添加说明或解释文本的方法&#xff0c;这些文本不会被执行。注释对于理解代码的目的、逻辑或特定部分的代码功能非常有帮助&#xff0c;尤其是在处理复杂或长的代码时。 一、…

当《黑神话:悟空》遇上openKylin,国产力量的极致碰撞!

万众瞩目的国产3A游戏巨作《黑神话&#xff1a;悟空》终于上线啦&#xff01;&#xff01;&#xff01; 在正式发售后不到24小时&#xff0c;Steam在线玩家峰值突破222万&#xff0c;在Steam所有游戏在线玩家历史峰值中排名第二。第一拨玩家纷纷晒出好评&#xff0c;称这款现象…

Python安装Crypto库报错:ModuleNotFoundError: No module named ‘Crypto‘

目录 from Crypto.Cipher import AES 1.解决方法 1、卸载Crypto和pycrypto库 2、安装pycryptodome库 二、另一种解决方法&#xff08;看的别人遇到的情况&#xff0c;我没有遇到这种情况&#xff09; from Crypto.Cipher import AES 在网上搜的教程使用第三方库实现AES算法…

消息中心业务系统集成方案:提升企业信息流动性与协作效率

在信息化时代&#xff0c;企业的业务系统之间需要实现高效的信息流动与协作&#xff0c;以支持动态的业务需求和快速的决策过程。消息中心作为企业信息管理的重要组成部分&#xff0c;通过整合各类消息和通知&#xff0c;能够提升信息传递的效率和准确性。本文将详细探讨消息中…

Nginx 配置指南

一、Nginx 简介 1.1 概述 Nginx 是一款高性能、轻量级的开源 Web 服务器和反向代理服务器&#xff0c;以其可靠性、丰富的功能和简单的配置而闻名。由 Igor Sysoev 开发&#xff0c;最初用于解决 C10K 问题&#xff0c;与传统的 Web 服务器相比&#xff0c;Nginx 采用异步事件…

使用stream()流合并两个列表

List<Author>结构如下&#xff1a; List<Reader>结构如下&#xff1a; 需求&#xff1a;将Author列表和Reader列表根据相同id合并到一个列表中 private static void mergeList() {List<Author> authors Author.getAuthors();List<Reader> readers …

阅读、分析和维护高质量开源软件有感——小计一笔

目录 一、问题分析 软件开发问题分析 动机 学什么 目的 二、要求 阅读 理解 运用 分析 评估 认知 三、案例选择 MiNotes”开源软件 方式 实践支撑软件工具 操作流程 应该学到的知识 学习过程 四、任务与输出 1.阅读开源软件 2.标注开源软件 3.分析开源…

iLogtail 开源两周年:感恩遇见,畅想未来

早在上世纪 60 年代&#xff0c;早期的计算机&#xff08;例如 ENIAC 和 IBM 的大型机&#xff09;在操作过程中会输出一些基本的状态信息和错误报告&#xff0c;这些记录通常通过打印机输出到纸带或纸卡上&#xff0c;用于跟踪操作流程和调试&#xff0c;最早期的日志系统借此…

前端必备:高效处理树形数据与数组的实用函数

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:Vue-树形数据处理|数组:实用函数封装 大家好&#xff0c;依旧青山&#xff0c;在开发项目过程中&a…

3、springboot时代背景

一、微服务 二、分布式 三、云原生 原生应用如何上云。 Cloud Native 上云的困难 服务自愈弹性伸缩服务隔离自动化部署灰度发布流量治理...... 上云的解决

人工智能算法工程师(中级)课程21-深度学习中各种优化器算法的应用与实践、代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程21-深度学习中各种优化器算法的应用与实践、代码详解。本文将介绍PyTorch框架下的几种优化器&#xff0c;展示如何使用PyTorch中的优化器&#xff0c;我们将使用MNIST数据集和一个简单…

云游戏畅玩黑神话悟空:使用 NVIDIA 4090 体验极致画质

​ 黑神话悟空 爽啦&#xff01;没有好配置又想玩《黑神话&#xff1a;悟空》的朋友们都爽啦&#xff01;自己没有好的 GPU&#xff0c;体验《黑神话&#xff1a;悟空》时画质不好玩的不舒心&#xff1f;厚德云来帮你解决问题&#xff01;厚德云上线了《黑神话&#xff1a;悟空…

机器学习第五十三周周报 MAG

文章目录 week53 MAG摘要Abstract1. 题目2. Abstract3. 预测标准3.1 问题提出3.2 数据预处理3.3 模型架构MAG3.4 时域故障模式识别3.5 故障检测器 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.4 实验结果4.5 结果分析 5. 结论小结参考文献 week53 MAG 摘要 本周阅读…

【ASPLOS2024】RECom:通过编译器技术加速推荐模型推理,论文中选并获得荣誉奖项!

2024年5月&#xff0c;关于推荐模型自动编译优化的论文《RECom: A Compiler Approach to Accelerate Recommendation Model Inference with Massive Embedding Columns》在系统领域顶会ASPLOS 2024上中选并进行了展示&#xff0c;并被授予了Distinguished Artifact Award 荣誉&…

基于springboot的招聘系统的设计与实现

TOC springboot614基于springboot的招聘系统的设计与实现--论文 研究背景 近年来&#xff0c;由于计算机技术和互联网技术的快速发展&#xff0c;使得所有企事业单位内部都是数字化、信息化、无纸化的发展趋势&#xff0c;随着趋势的发展&#xff0c;各种决策系统、辅助系统…

springboot安全在线学习平台---附源码131019

摘 要 这是采用springboot技术&#xff0c;SQL Server数据库实现的一个基于网络的在线学习系统。系统具有用户登录和注册、普通用户、课程分类、课程、购买表、课程上传等功能。在线学习是通过提供电子课件&#xff0c;让学生可以进行在线学习&#xff0c;并支持电子课件下载的…