C++新经典模板与泛型编程:萃取技术与策略技术,那个在C++标准库中无孔不入,无处不在的typename、using等关键字

  1. 了解标准库中许多萃取技术的实现方法
  2. 灵活运用并组合这些实现方法,写出 功能更强大、更优雅和实用的代码

固定萃取技术


#include <iostream>
// 固定萃取技术

template<typename T>
T funcsum(const T* begin, const T* end)
{
	T sum{}; // 数值类型初始化为0;指针型变量初始化为nullptr;布尔类型变量初始化为false
	for (;;) {
		sum += (*begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}


int main()
{

	int my_int_array1[] = { 10,15,20 };
	int my_int_array2[] = { 1000000000,1500000000,2000000000 }; // int类型的最大值在21亿至22亿之间
	char my_char_array[] = {"abc"}; // 97 ,98, 99

	std::cout << funcsum(&my_int_array1[0], &my_int_array1[2]) << std::endl;
	std::cout << funcsum(&my_int_array2[0], &my_int_array2[2]) << std::endl;
	std::cout << (int)funcsum(&my_char_array[0], &my_char_array[2]) << std::endl;


	return 0;
}

在这里插入图片描述
上述代码会实例化出以下两个funcsum函数:

int funcsum<int>(const int*,const int*)
char funcsum<char>(const char*,const char*)
// 也就是说funcsum()函数模板的类型模板T一次被推断成了int类型,一次被推断成了char类型。
// 所以从结果中可以看出,只有第一个结果正确,第二个和第三个结果都不正确,因为int类型能够保存的范围
// 为21亿多一点,不到22亿,但是my_int_array2的相加结果为45亿,所以出现了溢出,得出了205032704(溢出
// 的规则,极其重要)。第三个结果为char类型对应的ASCII码相加,所以得出97+98+99=294,但是char类型能够存
// 储的最大数值为127,所以结果值溢出,得到38.

如何解除保存的结果值溢出这个问题呢?

  1. 其实也比较好想象,如果用一个__int64类型(也叫long long类型或int64_t类型)的变量保存前两个数组(myintarray1和myintarray2)元素的和值,肯定是能够保存下的;如果用一个int类型的变量保存最后一个数组(mychararray)元素的和值,肯定也是能够保存下的。
  2. 那么可以修改一下funcsum()函数模板,新引入一个类型模板参数U,用于指定结果类型,这里为了代码书写方便,把新引入的类型模板参数U放在模板参数列表的前面。

#include <iostream>
// 固定萃取技术

template<typename T>
T funcsum(const T* begin, const T* end)
{
	T sum{}; // 数值类型初始化为0;指针型变量初始化为nullptr;布尔类型变量初始化为false
	for (;;) {
		sum += (*begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

template<typename U,typename T>
U funcsum(const T* begin, const T* end)
{
	U sum{};
	for (;;)
	{
		sum += (*begin);
		if (begin == end)
		{
			break;
		}
		++begin;
	}
	return sum;
}

int main()
{

	int my_int_array1[] = { 10,15,20 };
	int my_int_array2[] = { 1000000000,1500000000,2000000000 }; // int类型的最大值在21亿至22亿之间
	char my_char_array[] = {"abc"}; // 97 ,98, 99

	std::cout << funcsum(&my_int_array1[0], &my_int_array1[2]) << std::endl;
	std::cout << funcsum(&my_int_array2[0], &my_int_array2[2]) << std::endl;
	std::cout << (int)funcsum(&my_char_array[0], &my_char_array[2]) << std::endl;
	std::cout << std::endl;

	std::cout << funcsum<__int64>(&my_int_array1[0], &my_int_array1[2]) << std::endl;
	std::cout << funcsum<__int64>(&my_int_array2[0], &my_int_array2[2]) << std::endl;
	std::cout << (int)(funcsum<int>(&my_char_array[0], &my_char_array[2])) << std::endl;

	return 0;
}

在这里插入图片描述
上述代码会实例化以下两个funcsum()函数

 __int64 funcsum<__int64,int>(int const *,int const *) 
int funcsum<int,char>(char const *,char const *)
  1. 上述结果就是对的了。虽然结果问题解决了,但显然这种解决方案不太方便,每次调用funcsum()函数时都需要指定额外的模板参数。
  2. 有没有更好的解决方案呢?有,通过写一个trait类模板来解决,这里要写的trait类模板就是一个固定萃取类模板。简单地说,固定萃取类模板在这里就像一个中间件一样,夹在main()主函数中对funcsum()的调用代码与函数模板funcsum()代码之间,实现的功能如下。

(1). 当传入一个int类型(int类型数组myintarray1和myintarray2元素的类型),固定萃取类模板可以返回一个__int64类型(数组元素的和值类型)用来保存数组元素和值。
(2). 当传入一个char类型(char类型数组mychararray元素的类型),固定萃取类模板可以返回一个int类型(数组元素的和值类型)用来保存数组元素和值。
(3). 固定萃取类模板的“传入一种类型,萃取出(得到)另外一种类型”。这样,也就不需要在funcsum()函数模板中引入类型模板参数U了。而且这个固定萃取类模板可以在多个场合被复用。

// 固定萃取类模板的泛化版本
template<typename T>
struct SumFixedTraits;// 不需要实现代码,因为不需要用该版本进行实例化

// 各个固定萃取类模板的特化版本
// (1)传入的是char类型时,返回的是int类型
template<>
struct SumFixedTraits<char>  // char表示给进来的是char类型
{
	using sumT = int;
};

// (2)传入的是int类型时,返回的是__int64(long long/int64_t)类型
template<>
struct SumFixedTraits<int> // int表示传入的是int类型
{
	using sumT = __int64; // sumT为__int64类型,代表返回的是一个__int64类型
};

/* (3)... 其他传入的某个类型,返回的是另外一个类型,可以任意扩展出多个sumFixedTraits类模板的特化版本*/

有了SumFixedTraits类模板(是一个trait类模板)的各种特化版本之后,就可以借助这些特化版本重新改写前面求数组中元素和值的funcsum()函数模板。改写后的代码如下。


#include <iostream>


// 固定萃取类模板的泛化版本
template<typename T>
struct SumFixedTraits;// 不需要实现代码,因为不需要用该版本进行实例化

// 各个固定萃取类模板的特化版本
// (1)传入的是char类型时,返回的是int类型
template<>
struct SumFixedTraits<char>  // char表示给进来的是char类型
{
	using sumT = int;
};

// (2)传入的是int类型时,返回的是__int64(long long/int64_t)类型
template<>
struct SumFixedTraits<int> // int表示传入的是int类型
{
	using sumT = __int64; // sumT为__int64类型,代表返回的是一个__int64类型
};

/* (3)... 其他传入的某个类型,返回的是另外一个类型,可以任意扩展出多个sumFixedTraits类模板的特化版本*/

template<typename T>
auto funcsum(const T* begin, const T* end)
{
	using sumT = typename SumFixedTraits<T>::sumT; // 传入一个类型T,返回一个类型(sumT),这是固定萃取的运行

	sumT sum{};
	for (;;)
	{
		sum += (*begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

int main()
{

	int my_int_array1[] = { 10,15,20 };
	int my_int_array2[] = { 1000000000,1500000000,2000000000 }; // int类型的最大值在21亿至22亿之间
	char my_char_array[] = {"abc"}; // 97 ,98, 99

	std::cout << funcsum(&my_int_array1[0], &my_int_array1[2]) << std::endl;
	std::cout << funcsum(&my_int_array2[0], &my_int_array2[2]) << std::endl;
	std::cout << (int)funcsum(&my_char_array[0], &my_char_array[2]) << std::endl;


	return 0;
}

在这里插入图片描述
通过这个范例,不难看到固定萃取类模板(SumFixedTraits)起到的作用—通过某个类型,得到另外一个类型,这是模板与泛型编程很常见的一种应用。

嘛嘞个碧池,终于把using a = typename classx<T>::outputtype写完整了,之前尝试过几次,均以失败告终。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物联网安全芯片ACL16 采用 32 位内核,片内集成多种安全密码模块 且低成本、低功耗

ACL16 芯片是研制的一款32 位的安全芯片&#xff0c;专门面向低成本、低功耗的应用领域&#xff0c; 特别针对各类 USB KEY 和安全 SE 等市场提供完善而有竞争力的解决方案。芯片采用 32 位内核&#xff0c;片内集成多种安全密码模块&#xff0c;包括SM1、 SM2、SM3、 SM4 算法…

Unity传送门特效: The Beautiful Portal/Level up/Teleport/Warp VFX

7种不同风格的传送门特效! 每个传送门都有一个轻型和重型版本。 每个版本都有一个"无循环”和一个"无限”预制件:D 总共有28个预制件 -VFX完全使用Unity的粒子系统和基本的Unity着色器。 使用标准渲染管道中制作了这个资产。所以VFX的功能就像视频宣传片一样。 同时,…

Insomnia -- 非常nice的开源 API 调试工具

1. 这款开源 API 调试工具很棒&#xff01;&#xff01;&#xff01; Kong Insomnia是一个协作的开源API开发平台&#xff0c;可以轻松构建高质量的API&#xff0c;而不会像其他工具那样臃肿和混乱。 350开源插件 平衡能力和复杂性。当你需要的时候扩展工作流(当你不需要的时…

ubuntu20.04找不到#include<opencv/cv.h>文件

编译ROS包的时候出现错误&#xff1a;fatal error&#xff1a;opencv/cv.h : No such file or directory #include<opencv/cv.h> 查看opencv4版本&#xff1a; pk-config --modversion opencv4: 在opencv4中opencv2的cv.h融合进了imgproc.hpp里: 把源码中的#include …

正则化的概念

正则化的概念与用处 正则化&#xff1a;也叫规范化&#xff0c;在神经网络里主要是对代价函数高次项添加一些惩罚&#xff0c;防止其过拟合&#xff0c;相当于对某些特征的权重施加惩罚&#xff0c;降低其影响权重&#xff0c;防止过拟合。欠拟合时需要去掉正则化&#xff0c;…

探索Python的神奇力量:详解setattr函数的使用教程

概要&#xff1a; 在Python这个强大而灵活的编程语言中&#xff0c;有许多函数可以帮助开发者实现各种各样的任务。其中一个非常有用且功能强大的函数是setattr函数。setattr函数允许我们在运行时动态地设置对象的属性值&#xff0c;这为我们的代码增加了灵活性和扩展性。本文…

Embedding压缩之hash embedding

在之前的两篇文章 CTR特征重要性建模&#xff1a;FiBiNet&FiBiNet模型、CTR特征建模&#xff1a;ContextNet & MaskNet中&#xff0c;阐述了特征建模的重要性&#xff0c;并且介绍了一些微博在特征建模方面的研究实践&#xff0c;再次以下面这张图引出今天的主题&#…

文心一言插件开发全流程,ERNIE-Bot-SDK可以调用文心一言的能力

文心一言插件开发 前言插件插件是什么工作原理申请开发权限 开始第一步&#xff1a;安装python第二步&#xff1a;搭建项目manifest 描述文件&#xff1a;ai-plugin.json插件服务描述文件&#xff1a;openapi.yaml开发自己的plugin-server 第三步&#xff1a;上传插件 SDK相关链…

CentOS中安装数据库

1.下载 网址&#xff1a;https://dev.mysql.com/downloads/mysql/ 按如图选择&#xff0c;然后点击Download 这里它让我们登录&#xff0c;我们直接选择不登录&#xff0c;直接下载 2.关闭防火墙 systemctl disable firewalld3.正式安装 切换到/usr/local下 cd /usr/l…

岳阳楼3D模型纹理贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 岳阳楼&#xff0c;位于湖南省岳阳市岳阳楼区洞庭北路&#xff0c;地…

simulink同步机储能二次调频AGC,连续扰动负荷,储能抑制频率波动振荡震荡

若想观测二次调频性能&#xff0c;&#xff0c;切换为单一扰动即可&#xff0c;如下图所示。 AGC调速器都已经封装。后续也可加入风机光伏水电等资源。

时光相册下载 时光相册停运

可以私信或加底部联系方式&#xff0c;小偿支持 很遗憾听到这个消息。时光相册是一个让用户分享和保存珍贵回忆的平台&#xff0c;但由于各种原因&#xff0c;它可能已经停止运营了。建议你尽快备份你的相册和保存重要照片和视频。同时&#xff0c;可以考虑使用其他相册服务来…

数据结构 | 二叉树的各种遍历

数据结构 | 二叉树的各种遍历 文章目录 数据结构 | 二叉树的各种遍历创建节点 && 创建树二叉树的前中后序遍历二叉树节点个数二叉树叶子节点个数二叉树第k层节点个数二叉树查找值为x的节点二叉树求树的高度二叉树的层序遍历判断二叉树是否是完全二叉树 我们本章来实现二…

易点易动设备管理系统--提升设备能耗管理效率的工具

在当今的节能环保意识日益增强的社会背景下&#xff0c;设备能耗管理成为了市场推广人员关注的焦点之一。为了帮助市场推广人员提升设备能耗管理效率&#xff0c;易点易动设备管理系统应运而生。本文将详细介绍易点易动设备管理系统的功能和优势&#xff0c;以及如何借助该系统…

Python 对中文名称逐字按字母表进行排序并输出

使用场景 代码适用于需要对中文名称进行排序并规范化输出的情景&#xff0c;具体为处理一个包含中文姓名的文本文件&#xff0c;按姓名的拼音首字母进行排序&#xff0c;并以规范的格式输出。 排序规则&#xff1a; 将名称按照姓氏首字母A-Z的次序&#xff0c;进行排序&#x…

微服务实战系列之J2Cache

前言 经过近几天陆续发布Cache系列博文&#xff0c;博主已对业界主流的缓存工具进行了基本介绍&#xff0c;当然也提到了一些基本技巧。相信各位盆友看见这么多Cache工具后&#xff0c;在选型上一定存在某些偏爱: A同学说&#xff1a;不管业务千变万化&#xff0c;我对Redis的…

STM32-新建工程(标准库)

目录 STM32F10x新建工程&#xff08;标准库&#xff09; 移植文件夹 新建工程 添加启动文件和必需文件 在工程中加载新添加的文件 在工程中添加文件路径 在工程中添加main函数 添加lib库 添加必需文件 添加宏定义 点亮LED&#xff08;标准库&#xff09; STM32F10x新…

小型洗衣机什么牌子好又便宜?小型洗衣机全自动

随着科技的快速发展&#xff0c;现在的人们越来越注重自己的卫生问题&#xff0c;不仅在吃上面会注重卫生问题&#xff0c;在用的上面也会更加严格要求&#xff0c;而衣服做为我们最贴身的东西&#xff0c;我们对它的要求也会更加高&#xff0c;所以最近这几年较火爆的无疑是内…

【银行测试】第三方支付功能测试点+贷款常问面试题(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、第三方支付功能…

k8s 安装 Longhorn

Longhorn 的 helm 模板官网地址&#xff1a;Longhorn 加入仓库 helm repo add longhorn https://charts.longhorn.iohelm repo update开始部署 helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --version 1.5.3检查pod运行状态是…