C++可变参数模板类通过递归和特化方式展开

2024-05-10 10:28

本文主要是介绍C++可变参数模板类通过递归和特化方式展开,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

可变参数模版类有2种方式展开参数包:通过继承和通过递归+特化。在此只举例一个后着的例子以阐述展开的方式和过程。这些内容其实书上都有,我只是在看《深入C++11 代码优化与工程应用》一书中遇到了些困惑,可能书中的写法与我的理解不对版,在此记录一下从误解到了知的经过。

书中提到了通过模板元编程方式检查某个类型是否在一个类型列表里面,比如:

cout << Contains<int, char, int>::value << endl;
cout << Contains<int, char, float>::value << endl;
cout << Contains<int, char>::value << endl;
cout << Contains<int>::value << endl;

第一个模板实参int是要检查的类型,检查它是否存在于后面的列表中(通过可变参数)。只有第一个value是true,后面三个例子都是false。下面是实现代码:

template<typename T, typename... Rest>
struct Contains: std::true_type {};template <typename T, typename Head, typename... Rest> //partial specialization
struct Contains<T, Head, Rest...>
: std::conditional<std::is_same<T, Head>::value, std::true_type, Contains<T, Rest...> >::type {};template<typename T> //partial specialization
struct Contains<T>: std::false_type {};

除了第一行的template外,只要类名后面还带有有尖括号的叫做模板特化,也就是说这段code第一个模板是Contains普通模板,后面两个是Contains特化模板。对普通模板类、全特化类、偏特化类的匹配优先级从高到低进行排序是:

全特化类 > 偏特化类 > 主版本模板类

于是乎,当语句Contains<int, char, int>::value想要实例化时尽量先找特化版本,无特化可选才匹配普通版本,下面是借助C++ Insights工具展现模板展开的中间过程:

可以看到普通版本压根没有起作用,原书中普通模板的写法其实误导了我,以为Contains<int, char, int>匹配特化版而Contains<int, int>匹配普通版,其实不是的。这里只是给了个普通版本的实现,继承了std::true_type而已。

template<typename T, typename... Rest>
struct Contains: std::true_type {};

我如果想要将普通版仅有个声明,在我们当前需求下,经试验也是可以的:

template<typename T, typename... Rest>
struct Contains;

因为Contains<int, int>看似能同时满足特化版和普通版,它优先选择特化版,符合匹配优先级规律。

这篇关于C++可变参数模板类通过递归和特化方式展开的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/976179

相关文章

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

虚拟机与物理机的文件共享方式

《虚拟机与物理机的文件共享方式》文章介绍了如何在KaliLinux虚拟机中实现物理机文件夹的直接挂载,以便在虚拟机中方便地读取和使用物理机上的文件,通过设置和配置,可以实现临时挂载和永久挂载,并提供... 目录虚拟机与物理机的文件共享1 虚拟机设置2 验证Kali下分享文件夹功能是否启用3 创建挂载目录4

linux报错INFO:task xxxxxx:634 blocked for more than 120 seconds.三种解决方式

《linux报错INFO:taskxxxxxx:634blockedformorethan120seconds.三种解决方式》文章描述了一个Linux最小系统运行时出现的“hung_ta... 目录1.问题描述2.解决办法2.1 缩小文件系统缓存大小2.2 修改系统IO调度策略2.3 取消120秒时间限制3

Linux alias的三种使用场景方式

《Linuxalias的三种使用场景方式》文章介绍了Linux中`alias`命令的三种使用场景:临时别名、用户级别别名和系统级别别名,临时别名仅在当前终端有效,用户级别别名在当前用户下所有终端有效... 目录linux alias三种使用场景一次性适用于当前用户全局生效,所有用户都可调用删除总结Linux

MySQL中时区参数time_zone解读

《MySQL中时区参数time_zone解读》MySQL时区参数time_zone用于控制系统函数和字段的DEFAULTCURRENT_TIMESTAMP属性,修改时区可能会影响timestamp类型... 目录前言1.时区参数影响2.如何设置3.字段类型选择总结前言mysql 时区参数 time_zon

Mybatis官方生成器的使用方式

《Mybatis官方生成器的使用方式》本文详细介绍了MyBatisGenerator(MBG)的使用方法,通过实际代码示例展示了如何配置Maven插件来自动化生成MyBatis项目所需的实体类、Map... 目录1. MyBATis Generator 简介2. MyBatis Generator 的功能3

Python如何使用seleniumwire接管Chrome查看控制台中参数

《Python如何使用seleniumwire接管Chrome查看控制台中参数》文章介绍了如何使用Python的seleniumwire库来接管Chrome浏览器,并通过控制台查看接口参数,本文给大家... 1、cmd打开控制台,启动谷歌并制定端口号,找不到文件的加环境变量chrome.exe --rem

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC