c++新经典模板与泛型编程:const修饰符的移除与增加

news2025/2/25 5:16:33

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;
}

退化技术

  1. 某些类型一旦传递给函数模板(通过函数模板来推断相关的类型),那么推断出来的类型就会产生退化。所谓退化(decay),就是把类型中的一些修饰符丢弃了。例如,const int中的const丢弃后,就变成int类型,那么对于const int类型,int类型就是一种退化的表现。
  2. 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;
}

在这里插入图片描述

  1. 上述函数代表类型:void()
  2. 可以使用函数指针指向某种函数类型,如果指向void(),函数指针应该是void(*)()
  3. 如果不为函数名退化为函数指针写一个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;

	// 2
	Decay<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
	// 2
	Decay<decltype(testFunc2)>::type rfunc;
	std::cout << "rfunc类型为:" << typeid(decltype(rfunc)).name() << std::endl;
	rfunc();
#endif 

	// 3
	Decay<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;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学完就能涨薪5k的接口自动化测试框架pytest-多线程、多进程执行用例

有些项目的测试用例较多&#xff0c;测试用例时需要分布式执行&#xff0c;缩短运行时间。 pytest框架中提供可用于分布式执行测试用例的插件&#xff1a;pytest-parallel、pytest-xdist&#xff0c;接下来我们来学习这两个插件的使用方法。 pytest-parallel pytest-paralle…

绘制6层及以上PCB板,需要明白PCB板的结构和叠层

PCB主要由PP半固化片和core芯板压合而成&#xff0c;其中core芯板两面都有铜箔&#xff0c;是PCB板的导电介质&#xff1b;PP半固化片是绝缘材料&#xff0c;用于芯板的粘合。 在PP半固化片被层压后&#xff0c;其环氧树脂被挤压开来&#xff0c;将core芯板粘合在一起。 PCB的叠…

[NAND Flash 2.1] NAND Flash 闪存改变了现代生活

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< ​ 1989年NAND闪存面世了&#xff0c;它曾经且正在改变了我们的日常生活。 NAND 闪存发明之所以伟大&#xff0c;是因为&#xff0c…

抖音短视频账号矩阵系统开发新规则

一、抖音官方平台开发新规&#xff1a; 1.代发布管理应用api接口无法在做新的应用申请 仅针对企事业单位开放&#xff0c;目前要想开发新的抖音矩阵系统&#xff0c;就需要在原有的技术算法上进行新一步的调整。 能力介绍 网站应用开发者可以申请开通【代替用户发布内容到抖…

[NAND Flash 2.2] NAND闪存及控制器的市场趋势 [2023]

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< 一、NAND闪存市场分析 据欧洲知名半导体分析机构Yole发布的报告显示&#xff0c;2020年起&#xff0c;NAND闪存市场发展趋势保持稳定…

Web漏洞分析-SQL注入XXE注入(下)

随着互联网的不断普及和Web应用的广泛应用&#xff0c;网络安全问题愈发引起广泛关注。在网络安全领域中&#xff0c;SQL注入和XXE注入是两个备受关注的话题&#xff0c;也是导致许多安全漏洞的主要原因之一。本博客将深入研究这两种常见的Web漏洞&#xff0c;带您探寻背后的原…

@业务部门的,奉劝一句,赶紧掌握BI报表

趁着企业还在转型数字化&#xff0c;赶紧把BI报表掌握起来&#xff0c;以后BI大数据分析将是一个常用的企业级数据分析方向。掌握BI报表后&#xff0c;分析数据再也不用求人了。想分析什么数据&#xff0c;直接在BI平台上点击取数就是了&#xff0c;想怎么分析就怎么分析&#…

C++初学教程二

目录 一、格式化输出函数&#xff1a; 格式化输出函数printf() 1、格式 2、程序示例&#xff1a; 3、格式字符 4、举例 示例一&#xff1a; 示例二&#xff1a; ​示例三&#xff1a; 示例四&#xff1a; 示例五&#xff1a; 5、注意事项 二、格式化输入函数 格…

基于springboot+vue篮球联盟管理系统源码

&#x1f345; 简介&#xff1a;500精品计算机源码学习 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 文末获取源码 目录 一、以下学习内容欢迎交流&#xff1a; 二、文档资料截图&#xff1a; 三、项目技术栈 四、项目运行图 背景&#xff1a; 篮球运…

Chrome浏览器调整搜索标签页按钮位置

地址栏输入 chrome://flags 搜索 chrome-refresh-2023 第一项 修改为Enabled 标签搜索页按钮出现在chrome的左上角 修改为Default 标签搜索页按钮出现在chrome的右上角 修改完成后&#xff0c;点击Relaunch&#xff0c;重启浏览器&#xff0c;修改生效。

在发布应用程序时如何选择合适的分发方式?

大家好&#xff0c;我是咕噜-凯撒&#xff0c;在现代移动互联网的环境下&#xff0c;应用已经成为人们生活不可或缺的一部分&#xff0c;选择合适的分发方式对于应用的发展和成功来说至关重要。不同的分发方式有着自己的特点和优缺点&#xff0c;所以需要针对性地进行选择。下面…

2024王道考研计算机组成原理——存储系统

微信打开的时候会有一个人站在地球上&#xff0c;这个过程就是把程序从辅存转移到主存&#xff0c;数据只有调入主存当中才可以被CPU访问 cache&#xff1a;主存速度还是慢&#xff0c;为了进一步缓解CPU和主存之间的速度矛盾 在微信打视频聊天的时候&#xff0c;在这一段比较…

算法-03-排序-归并-快速排序

冒泡排序、插入排序、选择排序这三种排序算法&#xff0c;它们的时间复杂度都是O(n^2)&#xff0c;比较高&#xff0c;适合小规模数据的排序。如果数据量大&#xff0c;我们就需要使用到时间复杂度低的排序算法&#xff0c;归并排序和快速排序是复杂度为O(nlogn)的排序算法。 …

Image Segmentation Using Deep Learning: A Survey

论文标题&#xff1a;Image Segmentation Using Deep Learning:A Survey作者&#xff1a;发表日期&#xff1a;阅读日期 &#xff1a;研究背景&#xff1a;scene understanding,medical image analysis, robotic perception, video surveillance, augmented reality, and image…

【keepalived】高可用神器,实现应用的自动主备切换

目录 1.概述 2.配置 3.效果 4.keepalived主备切换原理 5.联系作者 1.概述 什么是keepalived&#xff1a; keepalived是一个基于VRRP协议来实现的服务高可用方案。VRRP协议&#xff0c;即虚拟路由冗余协议&#xff0c;其一开始提出来是为了解决局域网中配置静态网关出现单…

工业级路由器在智能交通系统(ITS)中的创新应用

智能交通系统&#xff08;ITS&#xff09;作为一种先进的交通管理与控制系统&#xff0c;旨在提高交通运输系统的效率、安全性和便捷性。随着科技的不断发展&#xff0c;智能交通系统已经成为城市交通管理的重要组成部分。而工业级路由器作为一种可靠的网络通信设备&#xff0c…

憋了个大招_群发版

大家好&#xff0c;我是良许。 憋了个大招&#xff0c;兄弟们&#xff01;我花了两个月的时间&#xff0c;搭建了一个自己的网站啦&#xff5e; 不卖关子&#xff0c;网站链接为&#xff1a; www.lxlinux.net/e/ 网站首页截图如下&#xff1a; 这个网站全部都是关于嵌入式及…

生物动力葡萄酒的快速指南

虽然我们大多数人都熟悉有机酿酒和农业&#xff0c;但围绕生物动力学仍有许多困惑和神秘。无论你是否完全陌生&#xff0c;或者你已经听到一些小道消息&#xff0c;我们在这里揭开这种独特的葡萄酒生产方法的神秘面纱。 生物动力葡萄酒就是一个更全面的有机酿酒过程&#xff0c…

详解nginx优势以及应用场景,实操编译安装和nginx版本平滑升级

目录 一、nginx的特点 那么nginx有哪些特点&#xff1f; 先讲nginx的优点&#xff1a; 缺点&#xff1a; 二、nginx与Apache的区别 三、nginx的应用场景 四、nginx为什么能支持高并发 五、为什么nginx不使用多线程 六、nginx的两种进程分别有什么作用 七、编译安装ngi…

web:[SUCTF 2019]CheckIn(一句话木马,.user.ini)

题目 页面显示 上传文件&#xff0c;随便上传一个文件试试 上传了一个文本&#xff0c;显示失败&#xff0c;不是图片 那就换图片马上传试试 不能包含<?,换一种写法&#xff0c;需要加上GIF89a&#xff0c;进行exif_imagetype绕过 上传成功 这里用.user.ini或者用post传参…