c++新经典模板与泛型编程:const修饰符的移除与增加
const修饰符的移除
让你来写移除const修饰符,你会怎么样来写?
😂😂trait类模板,如下
#include <iostream>// 泛化版本
template<typename T>
struct RemoveConst
{using type = T;
};// 特化版本
template<typename T>
struct RemoveConst<const T>
{using type = T;
};// 根据需要,可能还要增加其他特化版本
template<typename T>
using RemoveConst_t = typename RemoveConst<T>::type;int main()
{// nca 是int类型// c++标准库中的std::remove_const也比较类似RemoveConst_t<const int> nca = 15;// 可以给nca重新赋值nca = 18;return 0;
}
退化技术
- 某些类型一旦传递给函数模板(通过函数模板来推断相关的类型),那么推断出来的类型就会产生退化。所谓退化(decay),就是把类型中的一些修饰符丢弃了。例如,const int中的const丢弃后,就变成int类型,那么对于const int类型,int类型就是一种退化的表现。
c++标准库中有一个类模板std::decay,这个类模板的作用就是把一个类型退化掉(就是把类型中的一些修饰符丢掉)。
std::decay<const int&>::type nb = 28;// nb的类型为int类型std::cout << "nb的类型为:" << typeid(decltype(nb)).name() << std::endl;
如何实现一个类似std::decay功能的trait类模板呢?
// b.cpp
int g_array[10];// main.cpp
#include <iostream>// 泛化版本
template<typename T>
struct RemoveReference
{using type = T;
};// 特化版本
template<typename T>
struct RemoveReference<T&>
{using type = T;
};
template<typename T>
struct RemoveReference<T&&> // 这个特化能适应 const T&&应该是伴随我一生,难以理解的噩梦了
{using type = T;
};// 泛化版本
template<typename T>
struct RemoveConst
{using type = T;
};// 特化版本
template<typename T>
struct RemoveConst<const T>
{using type = T;
};// 根据需要,可能还要增加其他特化版本
template<typename T>
using RemoveConst_t = typename RemoveConst<T>::type;template<typename T>
struct RemoveCR : RemoveConst<typename RemoveReference<T>::type>
{ // 把const和引用修饰符去掉
};template<typename T>
using RemoveCR_t = typename RemoveCR<T>::type;// Decay的trait类模板
// 泛化版本
template<typename T>
struct Decay : RemoveCR<T>
{
};// 特化版本,这个特化版本没有继承任何父类
// 有边界数组转换成指针
template<typename T,std::size_t size>
struct Decay<T[size]>
{using type = T*;
};// 无边界数组转换成指针
template<typename T>
struct Decay<T[]>
{using type = T*;
};extern int g_array[];int main()
{RemoveCR_t<const int&&> rcrobj = 15; // rcrobj为int类型,只能叹为观止,惊叹rcrobj鬼斧神工地成了int类型int arr[2] = { 1,2 };Decay<decltype(arr)>::type my_array;std::cout << "my_array的类型为: " << typeid(decltype(my_array)).name() << std::endl;Decay<decltype(g_array)>::type my_array_2;std::cout << "my_array_2的类型为:" << typeid(decltype(my_array_2)).name() << std::endl;return 0;
}

- 上述函数代表类型:void()
- 可以使用函数指针指向某种函数类型,如果指向void(),函数指针应该是void(*)()
- 如果不为函数名退化为函数指针写一个Decay的特化版本,那么,传入testFunc2这个函数类型,
得到的返回类型依旧是void(),换句话说传入什么类型,就返回什么类型
#include <iostream>// 泛化版本
template<typename T>
struct RemoveReference
{using type = T;
};// 特化版本
template<typename T>
struct RemoveReference<T&>
{using type = T;
};
template<typename T>
struct RemoveReference<T&&> // 这个特化能适应 const T&&应该是伴随我一生,难以理解的噩梦了
{using type = T;
};// 泛化版本
template<typename T>
struct RemoveConst
{using type = T;
};// 特化版本
template<typename T>
struct RemoveConst<const T>
{using type = T;
};// 根据需要,可能还要增加其他特化版本
template<typename T>
using RemoveConst_t = typename RemoveConst<T>::type;template<typename T>
struct RemoveCR : RemoveConst<typename RemoveReference<T>::type>
{ // 把const和引用修饰符去掉
};template<typename T>
using RemoveCR_t = typename RemoveCR<T>::type;// Decay的trait类模板
// 泛化版本
template<typename T>
struct Decay : RemoveCR<T>
{
};// 特化版本,这个特化版本没有继承任何父类
// 有边界数组转换成指针
template<typename T,std::size_t size>
struct Decay<T[size]>
{using type = T*;
};// 无边界数组转换成指针
template<typename T>
struct Decay<T[]>
{using type = T*;
};extern int g_array[];// 简单的函数
void testFunc2()
{std::cout << "testFunc2()执行了" << std::endl;
}void rfunc()
{std::cout << "rfunc执行了" << std::endl;
}int main()
{RemoveCR_t<const int&&> rcrobj = 15; // rcrobj为int类型,只能叹为观止,惊叹rcrobj鬼斧神工地成了int类型int arr[2] = { 1,2 };Decay<decltype(arr)>::type my_array;std::cout << "my_array的类型为: " << typeid(decltype(my_array)).name() << std::endl;Decay<decltype(g_array)>::type my_array_2;std::cout << "my_array_2的类型为:" << typeid(decltype(my_array_2)).name() << std::endl;// 2Decay<decltype(testFunc2)>::type rfunc;std::cout << "rfunc类型为:" << typeid(decltype(rfunc)).name() << std::endl;rfunc();return 0;
}

现在容易理解写一个Decay特化版本把函数名(退化成)函数指针这件事了
因为函数可能有任何的返回类型以及任何数量和类型的参数,所以这个Decay的特化版本比较特殊
需要可变参模板来实现
#include <iostream>// 泛化版本
template<typename T>
struct RemoveReference
{using type = T;
};// 特化版本
template<typename T>
struct RemoveReference<T&>
{using type = T;
};
template<typename T>
struct RemoveReference<T&&> // 这个特化能适应 const T&&应该是伴随我一生,难以理解的噩梦了
{using type = T;
};// 泛化版本
template<typename T>
struct RemoveConst
{using type = T;
};// 特化版本
template<typename T>
struct RemoveConst<const T>
{using type = T;
};// 根据需要,可能还要增加其他特化版本
template<typename T>
using RemoveConst_t = typename RemoveConst<T>::type;template<typename T>
struct RemoveCR : RemoveConst<typename RemoveReference<T>::type>
{ // 把const和引用修饰符去掉
};template<typename T>
using RemoveCR_t = typename RemoveCR<T>::type;// Decay的trait类模板
// 泛化版本
template<typename T>
struct Decay : RemoveCR<T>
{
};// 特化版本,这个特化版本没有继承任何父类
// 有边界数组转换成指针
template<typename T,std::size_t size>
struct Decay<T[size]>
{using type = T*;
};// 无边界数组转换成指针
template<typename T>
struct Decay<T[]>
{using type = T*;
};extern int g_array[];// 简单的函数
void testFunc2()
{std::cout << "testFunc2()执行了" << std::endl;
}// 3
template<typename T,typename... Args>
struct Decay<T(Args...)> // 返回类型是T,参数是Args...
{using type = T(*)(Args...);
};int main()
{RemoveCR_t<const int&&> rcrobj = 15; // rcrobj为int类型,只能叹为观止,惊叹rcrobj鬼斧神工地成了int类型int arr[2] = { 1,2 };Decay<decltype(arr)>::type my_array;std::cout << "my_array的类型为: " << typeid(decltype(my_array)).name() << std::endl;Decay<decltype(g_array)>::type my_array_2;std::cout << "my_array_2的类型为:" << typeid(decltype(my_array_2)).name() << std::endl;#if 0// 2Decay<decltype(testFunc2)>::type rfunc;std::cout << "rfunc类型为:" << typeid(decltype(rfunc)).name() << std::endl;rfunc();
#endif // 3Decay<decltype(testFunc2)>::type rfunc_1;std::cout << "rfunc类型为:" << typeid(decltype(rfunc_1)).name() << std::endl;rfunc_1 = testFunc2;rfunc_1();return 0;
}

别名模板的威力
通过别名模板把Decay::type类型名简化成Decay_t,代码如下
template<typename T>
using Decay_t = typename Decay<T>::type;
于是,main()函数中的代码,可以写成
Decay<decltype(testFunc2)>::type rfunc;
就可以写成
Decay_t<decltype(testFunc2)> rfunc;
相关文章:
c++新经典模板与泛型编程:const修饰符的移除与增加
const修饰符的移除 让你来写移除const修饰符,你会怎么样来写? 😂😂trait类模板,如下 #include <iostream>// 泛化版本 template<typename T> struct RemoveConst {using type T; };// 特化版本 template…...
AUTOSAR汽车电子嵌入式编程精讲300篇-基于加密算法的车载CAN总线安全通信
目录 前言 研究现状 系统架构研究 异常检测研究 认证与加密研究 相关技术 2.1车联网 2.2车载网络及总线 2.2.1 CAN总线基础 2.2.2 CAN总线网络安全漏洞 2.2.3 CAN总线信息安全需求 2.3密码算法 2.3.1 AES算法 2.3.2 XTEA算法 CAN网络建模与仿真 3.1 CAN网络建模…...
4-Docker命令之docker start
1.docker start介绍 docker start命令是用来启动一个或多个已经被停止的docker容器。 2.docker start用法 docker start [参数] container [container......] [root@centos79 ~]# docker start --helpUsage: docker start [OPTIONS] CONTAINER [CONTAINER...]Start one or…...
AWS Remote Control ( Wi-Fi ) on i.MX RT1060 EVK - 2 “架构 AWS”
接续上一章节,我们把开发环境架设好之后,此章节叙述如何建立 AWS IoT 环境,请务必已经有 AWS Account,申请 AWS Account 之流程将不在此说明。 III-1. 登入AWS IoT, 在“管理”>“所有装置”>“实物”下点击“建…...
日志框架梳理(Log4j,Reload4j,JUL,JCL,SLF4J,Logback,Log4j2)
原文链接 日志框架发展历程 在了解日志框架时总会列出一系列框架:Log4j,Reload4j,JUL,JCL,SLF4J,Logback,Log4j2,这么多框架让人感到混乱,该怎么选取、该怎么用。接下来…...
内核无锁队列kfifo
文章目录 1、抛砖引玉2、内核无锁队列kfifo2.1 kfifo结构2.2 kfifo分配内存2.3 kfifo初始化2.4 kfifo释放2.5 kfifo入队列2.6 kfifo出队列2.7 kfifo的判空和判满2.8 关于内存屏障 1、抛砖引玉 昨天遇到这样一个问题,有多个生产者,多个消费者,…...
18、XSS——cookie安全
文章目录 1、cookie重要字段2、子域cookie机制3、路径cookie机制4、HttpOnly Cookie机制5、Secure Cookie机制6、本地cookie与内存cookie7、本地存储方式 一般来说,同域内浏览器中发出的任何一个请求都会带上cookie,无论请求什么资源,请求时&…...
从零开发短视频电商 Jmeter压测示例模板详解(无认证场景)
文章目录 添加线程组添加定时器添加HTTP请求默认值添加HTTP头管理添加HTTP请求添加结果断言响应断言 Response AssertionJSON断言 JSON Assertion持续时间断言 Duration Assertion 添加察看结果树添加聚合报告添加表格察看结果参考 以压测百度搜索为例 https://www.baidu.com/s…...
C++可以函数重载而C不可以的原因
函数重载是指在同一个作用域内,可以定义多个函数,它们具有相同的名称但是参数列表不同。函数重载的主要原理是函数的签名不同,而在 C 中,函数签名包括函数的名称和参数列表。而在 C 中,函数的标识仅依赖于函数的名称&a…...
Spark常见算子汇总
创建RDD 在Spark中创建RDD的方式分为三种: 从外部存储创建RDD从集合中创建RDD从其他RDD创建 textfile 调用SparkContext.textFile()方法,从外部存储中读取数据来创建 RDD parallelize 调用SparkContext 的 parallelize()方法,将一个存在的集合&…...
【华为数据之道学习笔记】3-1 基于数据特性的分类管理框架
华为根据数据特性及治理方法的不同对数据进行了分类定义:内部数据和外部数据、结构化数据和非结构化数据、元数据。其中,结构化数据又进一步划分为基础数据、主数据、事务数据、报告数据、观测数据和规则数据。 对上述数据分类的定义及特征描述。 分类维…...
电脑版便签软件怎么设置在桌面上显示?
对于不少上班族来说,如果想要在使用电脑办公的时候,随手记录一些常用的工作资料、工作注意事项等内容,直接在电脑上使用便签软件记录是比较方便的。电脑桌面便签工具不仅方便我们随时记录各类工作事项,而且支持我们快速便捷使用这…...
【华为数据之道学习笔记】2-建立企业级数据综合治理体系
数据作为一种新的生产要素,在企业构筑竞争优势的过程中起着重要作用,企业应将数据作为一种战略资产进行管理。数据从业务中产生,在IT系统中承载,要对数据进行有效治理,需要业务充分参与,IT系统确保遵从&…...
【IC前端虚拟项目】git和svn项目托管平台的简单使用说明
【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 代码托管在gitee平台上,进去后会看到文档目录“MVU芯片前端设计验证虚拟项目”和工程目录“mvu_prj”,可以通过git来下载工程: git clone gitgitee.com:gjm9999/ic_vi…...
C++ IO库
IO类 IO对象不能拷贝和赋值 iostream 表示形式的变化: 将100转换成二进制序列 然后格式化输出 x,y共用一块内存 输出的时候用不同的方式解析同一块内存 操作 格式化:内部表示转换为相应字节序列 缓存:要输出的内容放到缓存 编码转换&…...
Springboot 项目关于版本升级到 3.x ,JDK升级到17的相关问题
由于spring 停止对2.x 版本的维护,以及 jdk 频繁发布等客观因素,现需要对已有springboot 工程做一次全面升级;已因对市面上第三方等依赖库的兼容问题; 现有工程使用哥技术栈是版本: freemarker :2.3.32 spr…...
QGraphicsView实现简易地图7『异步加载-多瓦片-无底图』
前文链接:QGraphicsView实现简易地图6『异步加载-单瓦片-无底图』 前一篇文章提到的异步单瓦片加载,是指线程每准备好一个瓦片数据后,立刻抛出信号让主线程加载。而本篇异步多瓦片加载是指线程准备好所有瓦片数据后,一起抛出信号让…...
Spring Boot学习(三十三):集成kafka
前言 下面是zookeeper和kafka的官网下载地址,大家可以学习下载 zookeeper下载地址:http://zookeeper.apache.org/releases.html kafka下载地址:http://kafka.apache.org/downloads.html 1、添加依赖 在 pom.xml 文件中添加kafka依赖&am…...
MOSFET
MOSFET 电子元器件百科 文章目录 MOSFET前言一、MOSFET是什么二、MOSFET类别三、MOSFET应用实例四、MOSFET作用原理总结前言 MOSFET是一种常见的半导体器件,通过栅极电场控制通道区的导通特性,以控制电流流动。它在现代电子电路中发挥着重要的作用,并广泛应用于各种应用领域…...
DriveWorks——参数化设计非标定制利器
DriveWorks基本介绍 DriveWorks是一套被 SOLIDWORKS 认可为金牌合作伙伴产品的设计自动化软件。DriveWorks 可自动创建特定于订单的销售文档和 SOLIDWORKS 制造数据。减少重复性任务,消除错误,增加销售额,并在创纪录的时间内交付定制产品。 为…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
