C++11 可变参数模板

ops/2024/10/11 5:25:48/

C++11的新特性可变参数模板能够创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以这块还是比较晦涩的。

1. 函数模板

下面就是一个基本可变参数的函数模板,Args是一个模板参数包,args是一个函数形参参数包,声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。

template <class ...Args>
void ShowList(Args... args)
{}

上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数 包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的, 只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数,所以我们的用一些奇招来一一获取参数包的值。

2.递归函数方式展开参数包

// 递归终止函数
template<class T>
void ShowList(T value)
{cout << value << endl;}
// 展开函数
template<class T,class ...Args>
void ShowList(T value,Args ... args)
{cout << value << " ";ShowList(args...);
}
int main()
{ShowList(1);ShowList(1,'a');ShowList(1,'a',"abcde");return 0;
}

3.逗号表达式展开参数包

template<class T>
void PrintArg(T value)
{cout << value << " ";
}
// 展开函数
template<class ...Args>
void ShowList(Args ... args)
{int arr[] = { (PrintArg(args),0)... };cout << endl;
}
int main()
{ShowList(1);ShowList(1,'a');ShowList(1,'a',"abcde");return 0;
}

这种展开参数包的方式,不需要通过递归终止函数,是直接在函数体中展开的, PrintArg 不是一个递归终止函数,只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。 ShowList函数中的逗号表达式:(PrintArg(args), 0),也是按照这个执行顺序,先执行 PrintArg(args),再得到逗号表达式的结果0。同时还用到了C++11的另外一个特性——初始化列表,通过初始化列表来初始化一个变长数组, {(PrintArg(args), 0)...}将会展开成((PrintArg(arg1),0), (PrintArg(arg2),0), (PrintArg(arg3),0), etc... ),最终会创建一个元素值都为0的数组int arr[sizeof...(Args)]。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args) 打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包

4.STL容器中的empalce相关接口函数

template <class... Args>
void emplace_back (Args&&... args);

首先我们看到的emplace系列的接口,支持模板的可变参数,并且万能引用。

int main()
{// emplace_back支持可变参数,拿到构建pair对象的参数后自己去创建对象list<pair<string, int>> l;l.emplace_back(make_pair( "aaa", 1 ));l.emplace_back("bbb", 2);// push_back支持初始化列表传参l.push_back(make_pair("ccc", 3));l.push_back({ "ddd",4 });return 0;
}

那么在这里我们可以看到除了用法上,似乎和push_back没什么太大的区别,实际上,emplace_back优势更大。

减少不必要的复制或移动操作

emplace_back函数利用完美转发技术,直接在容器内部构造元素,从而避免了创建临时对象后再进行复制或移动的开销。这对于构造成本较高的对象尤为重要,因为它可以减少额外的资源消耗和性能损失. 


http://www.ppmy.cn/ops/86971.html

相关文章

Spark实时(六):Output Sinks案例演示

文章目录 Output Sinks案例演示 一、​​​​​​​File sink 二、​​​​​​​​​​​​​​Memory Sink 三、​​​​​​​​​​​​​​Foreach Sink 1、​​​​​​​foreachBatch 2、​​​​​​​​​​​​​​foreach Output Sinks案例演示 当我们对流式…

测桃花运(算姻缘)的网站系统源码

简介&#xff1a; 站长安装本源码后只要有人在线测算&#xff0c;就可以获得收入哦。是目前市面上最火的变现利器。 本版本无后台&#xff0c;无数据。本版本为开发的逗号联盟接口版本。直接对接逗号联盟&#xff0c;修改ID就可以直接运营收费赚钱。 安装环境&#xff1a;PH…

TVM、LLVM、CUDA 是三个不同的项目或技术

TVM、LLVM、CUDA 是三个不同的项目或技术,它们在编程和计算领域中各有其独特的用途和优势。以下是它们之间的关系及各自用途的详细说明: TVM TVM (Tensor Virtual Machine) 是一个端到端的深度学习编译栈,用于优化和部署深度学习模型到各种硬件后端。其主要功能包括: 模型…

vue3项目导入本地图标

一、下载图标库到本地 例如阿里图标库&#xff1a;iconfont-阿里巴巴矢量图标库 选所需图标收藏入库 2.自己的图标库下载入库的图标 3.下载的压缩包解压到本地&#xff0c;并将解压的图标文件拖拽进新创建的svg文件夹中 二、安装插件 1.安装svg图标引用所需插件 //命令行 n…

OS—文件系统

目录 一. 文件系统结构I/O 控制层基本文件系统文件组织模块逻辑文件系统 二. 文件系统布局文件系统在磁盘中的结构主引导记录(MasterBoot Record,MBR)引导块(boot block)超级块(super block)文件系统中空闲块的信息 文件系统在内存中的结构 三. 外存空间管理空闲表法空闲链表法…

匿名内部类

一个类的内部又完整的嵌套了另一个类结构&#xff0c;被嵌套的类称为内部类&#xff0c;嵌套其他的类称为外部类。 类的五大成员&#xff1a;属性、方法、构造器、代码块、内部类 内部类最大的特点的就是直接访问私有属性&#xff0c;并且可以体现类鱼类之间的包含关系。 基本…

Java 枚举详解:看完立马掌握!

大家好&#xff0c;我是小欧&#xff01; 今天我们来聊聊Java中的枚举&#xff08;Enum&#xff09;。枚举是Java中一种特殊的类型&#xff0c;用来表示一组固定的常量。如果你还没接触过枚举或者对它了解不多&#xff0c;别担心&#xff0c;看完这篇文章&#xff0c;你一定会对…

理解轮询与WebSocket:更新HTML内容的两种方式

理解轮询与WebSocket&#xff1a;更新HTML内容的两种方式 在开发Web应用时&#xff0c;更新页面内容的方式有很多&#xff0c;其中轮询&#xff08;Polling&#xff09;和WebSocket是两种常见的方法。了解这两种方法的区别、工作原理及其优缺点&#xff0c;有助于你选择最适合…