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对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

Spring Boot读取配置文件的五种方式小结

《SpringBoot读取配置文件的五种方式小结》SpringBoot提供了灵活多样的方式来读取配置文件,这篇文章为大家介绍了5种常见的读取方式,文中的示例代码简洁易懂,大家可以根据自己的需要进... 目录1. 配置文件位置与加载顺序2. 读取配置文件的方式汇总方式一:使用 @Value 注解读取配置方式二

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

将Java程序打包成EXE文件的实现方式

《将Java程序打包成EXE文件的实现方式》:本文主要介绍将Java程序打包成EXE文件的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录如何将Java程序编程打包成EXE文件1.准备Java程序2.生成JAR包3.选择并安装打包工具4.配置Launch4

springboot上传zip包并解压至服务器nginx目录方式

《springboot上传zip包并解压至服务器nginx目录方式》:本文主要介绍springboot上传zip包并解压至服务器nginx目录方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录springboot上传zip包并解压至服务器nginx目录1.首先需要引入zip相关jar包2.然

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文