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 制造数据。减少重复性任务,消除错误,增加销售额,并在创纪录的时间内交付定制产品。 为…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
PydanticAI快速入门示例
参考链接:https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...
