C++模板元编程(一)——可变参数模板

这个系列主要记录C++模板元编程的常用语法


文章目录

  • 引言
  • 语法
  • 应用
    • 函数模板
      • 可变参数的打印
      • 可变参数的最小/最大函数
    • 类模板
  • 参考文献


引言

在C++11之前,函数模板和类模板只支持含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含任意个(包括0个)模板参数,即可变参数模板。


语法

template<typename... Types>

其中 ... 可接纳的模板参数>=0
如果不希望产生模板参数个数为0的变长参数模板,则可以采用以下定义:

template<typename Head, typename... Tail>

由于多了Head类型,该模板必须有一个及以上的模板参数。


应用

函数模板

可变参数的打印

函数模板中一种常见的使用可变参数模板的场景是以递归的方式取出可用参数:

#include <iostream>

void print() {}

template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
	std::cout << firstArg << " " << sizeof...(args) << std::endl;
	print(args...);
}

template <typename... Types>
void print(const Types&... args) {
	std::cout << "print(...)" << std::endl;
}

int main(int argc, char* argv[]) {
	print(3.0f, "hello world", 10);
	return 0;
}

上面例子表示我们想要输出一个单精度浮点值+字符串+整型值:

  • 上面的 void print() {} 代表模板递归的终止。
  • print(args...) 展开参数,向下模板递归。
  • sizeof...(args) 得到参数的个数。

最终输出为

考虑如下情况,如果除了有上面的模板,我们还定义了一个完全泛化的模板:

template <typename... Types>
void print(const Types&... args) {
  std::cout << "print(...)" << std::endl;
}

那么输出结果是怎么样的?
答案是还是输出上面的值,这是因为编译器对于偏泛化和偏特化都满足的情况,会选择偏特化的模板。


可变参数的最小/最大函数

有时我们想得到可变参数的最小/最大函数,可以如下实现:

#include <iostream>

template <typename T>
T m_min(T value) {
  return value;
}

template <typename T, typename... Types>
T m_min(T value, Types... args) {
  return std::min(value, m_min(args...));
}

int main(int argc, char *argv[]) {
  std::cout << my_min(4, 3, 1, 2) << std::endl;

	return 0;
}


类模板

可变参数模板也可以用于类模板中,比如STL中的tuple

#include <iostream>

template<typename... Values> class tuple;
template<> class tuple<> {};

template<typename Head, typename... Tail>
class tuple<Head, Tail...>
	: private tuple<Tail...>
{
	typedef tuple<Tail...> inherited;
public:
	tuple() {}
	tuple(Head v, Tail... vtail) : m_head(v), inherited(vtail...) {}
	Head& head() { return m_head; }
	inherited& tail() { return *this; }
protected:
	Head m_head;
};

int main(int argc, char* argv[]) {
	tuple<float, std::string, int> t(3.0f, "hello world", 10);
	std::cout << t.head() << " " << t.tail().head() << " " << t.tail().tail().head() << std::endl;
	return 0;
}

通过可变参数模板,实现递归继承,根基类为 template<> class<>{},父类成员在内存中位于子类成员之前。

这里的输出为


参考文献

【C++】C++11可变参数模板(函数模板、类模板)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

保研复习 | 数据结构

目录 CH1 绪论☆ 数据项、数据元素、数据结构☆ 逻辑结构和存储结构的区别☆ 顺序存储结构和链式存储结构的比较☆ 算法的重要特性☆ 算法的复杂度 CH2 线性表☆ 单链表 CH3 栈、队列和数组☆ 栈和堆是什么&#xff1f;☆ 栈在括号匹配中的应用☆ 栈在表达式求值中的应用☆ …

Linux中的管道符‘|‘以及SQL(DQL,DCL)

ls 指令 语法&#xff1a; ls [选项][目录或文件] 功能&#xff1a; 对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件。 -…

【初阶数据结构】深入解析循环队列:探索底层逻辑

&#x1f525;引言 本篇将介绍如何实现循环队列并实现过程需要注意的事项&#xff0c;虽然篇幅较小&#xff0c;但是其中逻辑还是值得引人思考的&#xff0c;循环队列可以采用数组或链表实现&#xff0c;这篇将采用数组实现循环队列 &#x1f308;个人主页&#xff1a;是店小二…

Webpack: Loader开发 (1)

概述 如何扩展 Webpack&#xff1f;有两种主流方式&#xff0c;一是 Loader —— 主要负责将资源内容翻译成 Webpack 能够理解、处理的 JavaScript 代码&#xff1b;二是 Plugin —— 深度介入 Webpack 构建过程&#xff0c;重塑 构建逻辑。 相对而言&#xff0c;Loader 的职责…

阶段三:项目开发---搭建项目前后端系统基础架构:任务11:搭建项目后台系统基础架构

任务描述 1、了解搭建民航后端框架 2、使用IDEA创建基于SpringBoot、MyBatis、MySQL、Redis的Java项目 3、以原项目为参照搭建项目所涉及到的各个业务和底层服务 4、以原项目为例&#xff0c;具体介绍各个目录情况并参照创建相关文件夹 任务指导 1、讲框架的选择和原理 …

java信号量(Semaphore)

Java中的信号量&#xff08;Semaphore&#xff09;是一种用于控制多个线程对共享资源的访问的同步工具。它可以用来限制可以同时访问某些资源的线程数量。Semaphore 提供了一个计数器来管理许可证的获取和释放&#xff0c;每个许可证代表对资源的一次访问权限。 import java…

DB-GPT-PaperReading

DB-GPT: Empowering Database Interactions with Private Large Language Models 1. 基本介绍 DB-GPT 旨在理解自然语言查询,提供上下文感知响应,并生成高精度的复杂 SQL 查询,使其成为从新手到专家的用户不可或缺的工具。DB-GPT 的核心创新在于其私有 LLM 技术,该技术在…

CIRKD

环境不好满足&#xff0c;不建议复现

CSS【详解】长度单位 ( px,%,em,rem,vw,vh,vmin,vmax,ex,ch )

px 像素 pixel 的缩写&#xff0c;即电子屏幕上的1个点&#xff0c;以分辨率为 1024 * 768 的屏幕为例&#xff0c;即水平方向上有 1024 个点&#xff0c;垂直方向上有 768 个点&#xff0c;则 width:1024px 即表示元素的宽度撑满整个屏幕。 随屏幕分辨率不同&#xff0c;1px …

计网_计算机网络概述

2024.07.03&#xff1a;计算机网络概述 第1节 计算机网络概述 1.1 互连网与互联网1.1.1总结1.1.2 因特网(互联网)发展[自行了解] 1.2 计算机网络组成1.2.1 计算机网络组成方式11.2.2 计算机网络组成方式21.2.3 计算机网络组成方式3 1.3 三种交换方式1.3.1 电路交换(1) 电路交换…

Spring源码十五:Bean的加载

上一篇我们通过Spring源码十四&#xff1a;Spring生命周期介绍了refresh的最后两个方法&#xff0c;至此通过前面大概十篇左右的篇幅介绍完了Spring容器初始化&#xff0c;接下来&#xff0c;将进入Spring另外一个模块Bean相关的知识点。 在Spring框架中&#xff0c;Bean加载过…

人工智能时代打工人摸鱼秘籍(1)- 为啥说大模型像人?

人工智能以势不可挡的方式席卷全球。 所有公司&#xff0c;都在削尖脑袋想&#xff0c;如何在在产品、营销、运营、服务和管理上加持大人工智能的能力。 公司在卷生卷死的时候&#xff0c;有一批人已经偷偷在用大模型提&#xff08;摸&#xff09;效&#xff08;鱼&#xff09;…

从打印到监测:纳米生物墨水助力3D生物打印与组织监测平台?

从打印到监测&#xff1a;纳米生物墨水助力3D生物打印与组织监测平台&#xff1f; 在 3D 组织工程中&#xff0c;纳米生物墨水是将纳米材料与 ECM 水凝胶结合&#xff0c;以提高其打印性和功能性的重要策略。纳米生物墨水可以增强水凝胶的机械性能、导电性、生物活性&#xff…

2024高考作文题“人工智能”

今年开年到现在&#xff0c;明显的感受就是&#xff0c;咨询人工智能机器人的客户比往年更多了。什么原因&#xff0c;是因为人工成本太高了&#xff0c;今年整体经济环境变差&#xff0c;招不起人&#xff0c;所以想用AI机器人来降低用工成本吗&#xff1f; 还是说因为语音线路…

JVM专题之G1垃圾收集器下

索引(记录)的源码的工作流程图如下: CSet(Collection Set 回收集合) 收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。因此无论是年轻代收集,还是混合收集,工作的机…

PsQuerySystemDllInfo逆向

typedef struct _SYSTEM_DLL_ENTRY {ULONG64 type;UNICODE_STRING FullName;PVOID ImageBase;PWCHAR BaseName;PWCHAR StaticUnicodeBuffer; }SYSTEM_DLL_ENTRY, * PSYSTEM_DLL_ENTRY; 返回值为上面的结构体指针 验证 type: fullname inagebase: pwchar basename PWCHAR …

Spring源码十六:Bean名称转化

在上一篇Spring源码十五&#xff1a;Bean的加载 中我们通过前面的案例方法&#xff0c;找到了Spring真正开始创建Bean的入口&#xff0c;也就是doGetBean方法。该方法是Spring框架中Bean创建与获取的核心逻辑&#xff0c;实现了复杂的Bean生命周期管理。通过单例缓存、合并Bean…

NLP简介

自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此&#xff0c;这一领域的研究将涉及自…

保存在FinalShell服务器登录密码忘记了,如何快速获取到

一、从FinalShell获取服务器基本信息 如图操作会导出一个json文件&#xff0c;可以直接保存在桌面&#xff0c;或者其他位置 json格式如下&#xff1a; {"forwarding_auto_reconnect":false ,"custom_size":false ,"delete_time":0 ,"sec…

从0到1制作单只鳌虾运动轨迹追踪软件

前言 需要准备windows10操作系统&#xff0c;python3.11.9&#xff0c;cuDNN8.9.2.26&#xff0c;CUDA11.8&#xff0c;paddleDetection2.7 流程&#xff1a; 准备数据集-澳洲鳌虾VOC数据集 基于RT-DETR目标检测模型训练导出onnx模型进行python部署平滑滤波处理视频帧保留的…