变长模板:模板参数包和函数参数包

2023-11-01

模板参数包

我们先看看变长模板的语法,以tuple为例:

template<typename... Elements> class tuple;

可以看到,我们在标识符Elements之前使用了省略号(三个点)来表示该参数是变长的。在C++11中,Elements被称作是一个“模板参数包”,这是一种新的模板参数类型。有了这样的参数包,类模板就可以接受任意多个参数作为模板参数。比如:

tuple <int, char,double>

与普通的模板参数类似,模板参数包也可以是非类型的,比如:

template<int... A> class NonType {};
NonType<1, 2, 2>nValues;

该声明方式相当于:

template<int, int, int> class NonType {};
NonType<1, 2, 2>nValues;

一个模板参数包在模板推导时会被认为是模板的单个参数,为了使用模板参数包,我们总是需要将其解包,在C++11中,这通常是通过一个名为包扩展的表达式来完成,比如:

template<template T1, template T2>class TClassB{};
template<typename ... A> class TClassA : private TClassB<A...> {};
TClassA<int, double> xy;

这里我们为类模板声明了一个参数包A,而使用参数包A...则是在TClassA的私有基类TClass<A...>中,最后一个表达式声明了一个基类为B<X,Y>的模板类TClassA的对象。其中X、Y两个模板参数先是被打包为参数包A,而后又在包扩展表达式A...中被还原。

不过上面的例子,只能接受两个参数类型,那如何才能利用模板参数包及包扩展,使得模板能够接受任意多的模板参数,且均能实例化出有效的对象呢?

在C++11中,这一答案是使用数学的归纳法,转换为计算机能够实现的手段就是递归。通过定义递归的模板偏特化定义,可以使得模板参数包在实例化时能够层层展开,直到参数包中的参数逐渐耗尽到达某个数量的边界为之。下例是简化的tuple实现:

template<typename...Element>class tuple;		//变长模板的声明;
template<typename Head, typename... Tail>		//递归的偏特化定义
class tuple<Head, Tail...> :private tuple<Tail...>
{
	Head head;
};

template<> class tuple<>{};			    //边界条件

我们首先声明了变长模板类tuple,其只包含一个模板参数,即Elements模板参数包。此外,我们又偏特化地定义了一个双参数的tuple的版本。我们将Head型的数据作为tuple<Head,Tail...>的第一个成员,而将使用了包扩展表达式的模板类tuple<Tail...>做为私有基类。这样当程序员实例化一个形如tuple<double,int, char, float>的类型时,则会引起基类的递归构造,这样的递归在tuple的参数为0个的时候结束。因此我们又定义了边界条件。

tuple<double,int, char,float>实例化后的继承结构如下图,我们用方框表示类型,而方框内的方框表示类型由其内部的方框所代表的类型私有派生而来。

 函数参数包

在C++11中,还可以声明变长模板的函数,对于变长模板的函数而言,除了声明可以容纳变长个模板参数的模板参数包之外,相应地,变长的函数参数也可以声明成函数参数包。比如:

template<typename...T>void foo(T... args) {};

注意:在C++11中,标准要求函数参数包必须唯一,且是函数的最后一个参数,而模板参数包没有这样的要求。

有了函数参数包和模板参数包就可以实现C中变长函数的功能了。一起看一下Printf的例子:

#include <iostream>
#include <stdexcept>

using namespace std;

void Printf(const char *s)
{
	while (*s)
	{
		if (*s == '%' && *++s != '%')
		{
			throw runtime_error("invalid format string");
		}

		cout << *s++;
	}
}

template<typename T, typename...Args>
void Printf(const char*s, T value, Args... args)
{
	while (*s)
	{
		if (*s == '%' && *++s != '%')
		{
			cout << value;
			return Printf(++s, args...);
		}
		cout << *s++;
	}
	throw runtime_error("extra args provided to Printf");
}
int main()
{	
	Printf("hello %d %s \n", 5, "world");
}

Printf是一个变长函数模板,功能等同于printf。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

变长模板:模板参数包和函数参数包 的相关文章

  • docker安装nacos2.0.3并配置mysql

    1 拉取镜像 docker pull nacos nacos server 2 0 3 2 创建数据目录 mkdir p mydata nacos2 0 3 logs mkdir p mydatadata nacos2 0 3 conf 3
  • Java 包(package)

    为了更好地组织类 Java 提供了包机制 用于区别类名的命名空间 包的作用 1 把功能相似或相关的类或接口组织在同一个包中 方便类的查找和使用 2 如同文件夹一样 包也采用了树形目录的存储方式 同一个包中的类名字是不同的 不同的包中的类的名
  • linux安装virtualbox命令,如何在CentOS 7.5上安装VirtualBox

    VirtualBox是一款开源的跨平台虚拟化软件 允许您同时运行多个客户操作系统 虚拟机 在本教程中 我们将向您展示如何从CentOS 7系统上的Oracle存储库安装VirtualBox 前提条件 在继续本教程之前 请确保以具有sudo权
  • 为网站接入前端异常监控系统 Sentry

    背景 众所周知 现在前端异常监控在实际生产环境中越来越重要了 通过给网站接入前端异常监控系统 我们能获得以下几个好处 收集页面的错误信息 辅助定位代码错误位置 在用户报障前发现问题 这对于提升线上系统质量 降低线上故障数量 都具有非常重要的
  • 【mysql基础系列十一】用户权限管理

    用户权限管理 在不同的项目中给不同的角色 mysql客户端用户 通常为开发者 不同的权限 为了保证数据库的数据安全 用户管理 mysql需要客户端进行连接认证才能进行服务器操作 需要用户信息 mysql中所有的用户 指mysql客户端用户
  • Spring的生态圈、Spring全家桶

    Springboot是伴随spring4诞生的 除了springboot之外 spring作为企业级应用开发的轻量级解决方案提供了许多子项目 这些子项目可以更好地理解其设计架构 思想并使用spring spring的整个生态系统包括以下内容
  • jenkins 链接远程服务器,执行shell脚本后台启动java工程,项目已启动成功,jenkins界面仍在转圈

    jenkins 链接远程服务器 执行shell脚本后台启动java工程 项目已启动成功 jenkins界面仍在转圈 如图 之前的shell nohup java jdk1 8 0 221 bin java jar jenkins proje
  • flink-sql读写hive-1.15

    1 版本说明 本文档内容基于flink 1 15 x 其他版本的整理 请查看本人博客的 flink 专栏其他文章 1 1 概述 Apache Hive 已经成为了数据仓库生态系统中的核心 它不仅仅是一个用于大数据分析和ETL场景的SQL引擎
  • MySql5.7 直接拷贝数据文件后出现table xxx doesn’t exist

    MySQL备份或者转移数据库时有一种方便的方法 就是直接拷贝MySQL目录下 data文件夹下对应的数据库文件夹 但当粘贴到另外的服务器下的data文件夹下后 虽然打开数据库后能看到各个table 但使用时却会提示table xxx doe
  • java concurrency基础

    本来是学习volatile关键字的 结果连带学习了这么多知识点 慢慢看吧 标记一下 1 深入浅出java concurrency http www blogjava net xylz archive 2012 05 30 325587 ht
  • 如何给6个整数的一维数组某个元素赋值_C++基础知识篇:C++ 数组

    C 支持数组数据结构 它可以存储一个固定大小的相同类型元素的顺序集合 数组是用来存储一系列数据 但它往往被认为是一系列相同类型的变量 数组的声明并不是声明一个个单独的变量 比如 number0 number1 number99 而是声明一个
  • 用好这 28 个工具,开发效率爆涨|云效工程师指北

    大家好 我是秦世成 我在云效负责制品仓库Packages的开发工作 作为一个有多年经验的资深CRUD后端工程师 使用过很多日常开发所需的工具软件 其中不少能堪称为 神器 这些 神器 能极大的提升日常开发的效率 小到一个复制粘贴操作 大到开发
  • Wireshark

    抓包工具 抓包工具是拦截查看网络数据包内容的软件 抓包工具由于其可以对数据通信过程中的所有lP报文实施捕获并进行逐层拆包分析 一直是传统固网数通维护工作中罐常用的故障排查工具 业内 流行的抓包软件有很多 Wireshark SnifferP
  • 【vue】$set怎么使用

    vue中在data 里的数据才是响应式的 有的场景 比如说后端返回的接口对象里 想再增加一个属性 作为响应式 这时候可以用到 set添加 set总共三个参数 第一个为当前对象 第二个为属性名 第三个为属性值
  • nebula graph 常用命令(updating)

    文章目录 管理Storage主机 空间 创建标签 边 点 增 改 删除点和边 索引 创建索引 重建索引 drop tag 查询 match go FETCH LOOKUP 统计 管理Storage主机 从 3 0 0 版本开始 在配置文件中
  • 循环遍历的区别

    循环遍历的区别 forEach 直接循环数组 没有返回值 如何结束循环 是结束本次循环是可以使用return 但是结束全部循环return无效 原因 好像是因为forEach不管符不符合都会走完所有的循环 所以return结束本次循环后 会
  • 【markdown工具配合图床】PicGo图床配置教程,一秒读懂配置

    前言 看到这篇文章的大佬 我默认大家都会配置git 已经配置好ssh公钥 此时你看到的这篇文章就是基于markdown工具 VSCode Typora 编写的 PicGo作为图床转换工具 并配合gitee作为图片服务器 仓库 个人设置找到私
  • tms web core 调用webapi的方法

    webhttprequest组件属性设置 header Cache Control no cache no store must revalidate Content Type application x www form urlencod
  • 紫书《算法竞赛入门经典》

    紫书 算法竞赛入门经典 题目一览 第3章 数组和字符串 例题 UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 340 Master Mind Hints UVA 158

随机推荐

  • 利用StringEscapeUtils对字符串进行各种转义与反转义(Java)

    转载自 Java我人生 陈磊兴 原文出处 http blog csdn net chenleixing article details 43456987 apache工具包common lang中有一个很有用的处理字符串的工具类 其中之一就
  • renren-generator项目启动后无法打开网页

    解决
  • JavaScript对象的定义以及创建对象的三种方式和遍历对象的介绍以及相对应的案例

    JavaScript对象 1 什么是对象 在JavaScript中 对象是一组无序的相关属性和方法的集合 所有的事物都是对象 例如字符串 数值 数组 函数等 对象是由属性和方法组成的 属性 事物的特征 在对象中用属性来表示 常用名词 方法
  • ElasticSearch 之 _score

    ElasticSearch 之 score 1 什么是 score 2 布尔模型 3 词频 逆向文档频率 TF IDF 3 1 词频 3 2 逆向文档频率 3 3 字段长度归一值 3 4 结合使用 4 向量空间模型 5 Lucene的实用评
  • MySQL免安装版下载及安装(完整版)

    1 安装包下载 1 进入官网下载 MySQL Download MySQL Community Server Archived Versions 2 压缩包解压到你要安装的位置 2 MySQL配置 1 以管理员身份打开命令 2 跳转到MyS
  • 圆形图片

    public class RoundImageView extends ImageView public RoundImageView Context context super context TODO Auto generated co
  • 期货,实例讲述

    说到 期货 有人马上就会想到一大堆的粮食或者金属品的满天飞 其实不然 如果要每个人都抱一大堆的粮食回家的话我想经纪公司存在也没有它实质的意义了 其实对于大多数的投机者来说 期货 就和 股票 一样 都是一种低买高卖的挣钱工具 它并不需要你把一
  • 分布式复习1~3章

    参考 学校ppt 整体 爹 https zhuanlan zhihu com p 341814546 时间和时钟 https blog csdn net fragile98 article details 113695334 分布式系统的时
  • 利用ESP8266模块实现远程用手机控制开关

    利用ESP8266模块实现远程用手机控制开关 文章目录 前言 一 ESP8266是什么 二 使用步骤 1 密钥与核心库 2 连接Wi Fi 3 手机端控制函数 总结 插入链接与图片 列表 前言 随着万物联网的时代到来 通过互联网来控制已经越
  • AIGC 的概念与内涵

    导读 目前 对AIGC这一概念的界定 尚无统一规范的定义 国内产学研各界对于AIGC的理解是 继专业生成内容 ProfessionalGeneratedContent PGC 和用户生成内容 UserGeneratedContent UGC
  • 多线程-线程通信(wait-notify,await-single,park-unpark)

    在多线程场景中 如有些线程需要依赖另外线程的结果而继续执行 如多个线程处理请求 有的处理的快有点慢 快的需要等待慢的线程结果一起提交执行结果 都会涉及到线程间的通信 就是A线程告知B线程处理的结果是怎么样 B线程再执行对应逻辑 通信比较经典
  • Laravel从入门到实践

    Laravel从入门到实践 版本 Laravel版本 8 75 0 安装与配置 使用Docker 安装项目 curl s https laravel build betterlife bash 启动项目 cd betterlife vend
  • 笔记:RTSP在线视频流资源地址

    1 在线视频流地址 rtsp wowzaec2demo streamlock net vod mp4 BigBuckBunny 115k mov 2 播放软件 vlc 下载地址 Downloads VideoLAN 使用如下 打开媒体 打开
  • 股票集合竞价规则详解,什么是集合竞价?集合竞价技巧分析

    股票集合竞价规则是每一个新入股市的朋友都应该首先掌握的一个知识要点 然而很多新入市的朋友对于股票集合竞价规则了解的是很少的 今天为了帮助更多的朋友掌握这个规则 笔者作为金融市场的铁杆粉丝 从三年前开始 就对金融市场的理论和实践方面的认识逐渐
  • 【空气检测仪专题】9.画PCB图

    空气检测仪专题 9 画PCB图 移植了EmWin并写了demo程序 效果如下 很久没有画PCB图了 慢慢画呗
  • 北大网站服务器关闭,北京大学网络服务

    nbsp 1 如何在Windows2000环境下配置静态IP地址 第一步 选择 控制面板 选择 网络和拨号连接 第二步 鼠标右键选择 本地连接 或者相应的网卡名称 选择 属性 第三步 选择 TCP IP协议 第四步 配置相应的参数 IP地址
  • 查看SELinux状态&关闭SELinux

    1 查看SELinux状态 1 1 getenforce getenforce 命令是单词get 获取 和enforce 执行 连写 可查看selinux状态 与setenforce命令相反 setenforce 命令则是单词set 设置
  • Qt获取当前时间(超详细)

    Qt获取当前时间 超详细 转载自别的网站 时间日期是经常遇到的数据类型 Qt 中时间日期类型的类如下 QTime 时间数据类型 仅表示时间 如15 23 13 QDate 日期数据类型 仅表示日期 如2017 4 5 QDateTime 日
  • unity timeline 用脚本添加事件运用

    ExposedReference
  • 变长模板:模板参数包和函数参数包

    模板参数包 我们先看看变长模板的语法 以tuple为例 template