template——模板进阶(C++)

news2024/12/23 4:32:35

        在之前的文章中,介绍了模板初阶:Cpp_桀桀桀桀桀桀的博客-CSDN博客

        在本篇中将会对模板进一步的讲解。本篇中的主要内容为:非类型模板参数、函数模板的特化、类模板的特化(其中包含全特化和偏特化),最后讲解了模板的分离编译问题,以及出现链接错误的原因。

        目录如下:

目录

1. 非类型模板参数

1.1 模板的按需实例化

2. 模板的特化

2.1 特化的概念

2.2 函数模板特化

2.3 类模板特化

3. 模板的分离编译

3.1 模板的分离编译及其原理

1. 非类型模板参数

        模板参数分为:类类型形参非类型形参

        类型形参:出现在模板参数列表中,跟在 class 或者 typename 之类的参数类型名称之后。

        非类型形参:使用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

        如下所示的两份代码:

namespace MyArray1
{
// 使用宏定义
#define N 10
	// 定义一个模板类型的静态数组
	template<class T>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { return _array[index]; }
		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }
	private:
		T _array[N];
		size_t _size;
	};
}

namespace MyArray2
{
	// 使用宏定义
	// 定义一个模板类型的静态数组
	template<class T, size_t N = 10>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { return _array[index]; }
		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }
	private:
		T _array[N];
		size_t _size;
	};
}

        如上所示,当我们想要写一个常量数组类,我们可以使用两种方法,一种是使用宏定义来确定数组的大小,另一种是使用非类型模板参数来充当数组的大小,我们在使用非类型模板参数的时候,也可以像使用函数参数一样,给一个缺省值。

        关于使用其他的非类型模板参数,我们的非类型模板参数只能使用整型做模板参数,对于其他非类型的模板参数,只有到 C++20 标准之后才可以使用。如下:

        关于类(函数)模板传参与函数传参的时刻:对于类模板传参而言,传参的时候是在编译阶段,因为模板属于一个半成品,在编译阶段需要使用传入的参数来生成确定的类(代码);而对于函数传参而言,函数传参是在运行时传参,将我们需要运行的参数传入函数中进行计算。

1.1 模板的按需实例化

        在模板实例化的时候,并不会检测语法错误,如下:

        我们在函数中调用 assert 函数和 size 函数都出现了语法错误,但是我们在生成解决方案的时候却可以通过,这是因为对于模板而言,这是一个半成品,在语法编译的的时候,因为并没有调用类函数,所以并不会检测语法。

        当我们实例化一个对象的时候,是否会检测出错误呢?如下:

        当我们实例化一个对象的时候,调用其中一个函数的时候,也还是不会检测出错误,这是因为按需实例化,不仅仅是类的按需实例化,类函数也是按需实例化,只有当调用的函数出现错误的时候,才会检测出来

        对于模板实例化的步骤为:根据模板实例化 --> 半成品模板 --> 实例化成具体的类/函数 --> 语法编译。

2. 模板的特化

2.1 特化的概念

        通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要我们进行特殊的处理,如下:

        如上所示,当使用指针进行比较的时候,原本应该输出为0,但是却输出为1,这是因为在 Less 中并没有比较指针指向的内容重载函数,而是直接的比较指针的大小,所以输出的结果显示错误。

        这个时候,我们就需要对模板进行特化,即:在原模板的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化类模板特化

2.2 函数模板特化

        函数模板特化的步骤

        1. 必须要现有一个基础的函数模板;

        2. 关键字 template 后面接一个空的<>;

        3. 函数名后面跟一对尖括号,尖括号内指定需要特化的类型;

        4. 函数形参必须要和模板函数的基础参数类型完全相同,如果不同,编译器可能会薄一些奇怪的错误。

        如下:

template<class T>
bool Less(T x, T y) {
	return x < y;
}

// 函数模板特化
template<>
bool Less<Date*>(Date* x, Date* y) {
	return *x < *y;
}

// 函数重载
bool Less(Date* x, Date* y) {
	return *x < *y;
}

        如上所示的函数模板特化形式,就可以解决这样的问题,但是其实我们也可以写一个重载函数来解决这个问题。通常情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现功能,最好直接写一个重载函数,通常不建议写函数模板特化。

2.3 类模板特化

        关于类模板的特化其中包含全特化偏(半)特化

        其中全特化为将模板参数列表中所有的参数都确定化,如下:

template<class T1, class T2>
class A {
public:
	A() { cout << "A<T1, T2>" << endl; }
private:
	T1 _a1;
	T2 _a2;
};

// 将参数列表中所有的参数都确定化
template<>
class A<int, char> {
public:
	A() { cout << "A<int, char>" << endl; }
private:
	int _a1;
	char _a2;
};

void Test01() {
	A<int, int> aa1;
	A<int, char> aa2;
}

        关于偏特化,也分为两种类型,一种是将模板参数类表中的一部分参数特化,另一种是将参数进一步的限制,如下:

// 将模板参数表中的一部分参数特化
template<class T1>
class A<T1, int> {
public:
	A() { cout << "A<T1, int>" << endl; }
private:
	T1 _a1;
	int _a2;
};

// 将模板参数表中的参数进一步的限制
template<class T1,class T2>
class A<T1*, T2*> {
public:
	A() { cout << "A<T1*, T2*>" << endl; }
private:
	T1 _pa1;
	T2 _pa2;
};

3. 模板的分离编译

        首先关于什么是分离编译,分离编译就是将一个类或者一个函数的声明与定义分别放在不同的文件之中,然后在生成目标文件的过程中,需要将所有目标文件(每一个源文件都会生成一个目标文件)链接起来,形成一个单一的可执行文件的过程叫做分离编译模式

3.1 模板的分离编译及其原理

        关于模板的编译与分离,就是将一个模板的声明放在一个 .h 文件中,然后将一个模板的定义放在另一个 .cpp 文件之中,如下:

        如上图所示,当我们将模板的声明与定义分隔开的时候,调用对应函数的时候就会导致报错(若我们不调用对应的函数的时候,就不会报错,这是因为对于模板而言,只是一个半成品,只有按需实例化的时候才会检测出错误),链接错误。

        出现这种错误的原因:

        当我们声明和定义分离的时候,我们将头文件包含在当前 main 函数所在的文件中,在预处理阶段,会将头文件在 main 函数所在的文件展开,然后在编译阶段,我们将我们的模板进行实例化,根据传入的模板参数进行实例化,有多少种就会实例化多少种代码,然后在链接的阶段,会去找我们调用的函数,但是在展开实例化的函数中,我们只有声明,然后就会去分离定义的文件中寻找,当在其他文件中找到定义的时候,这里的定义并没有在编译阶段跟着实例化,仍然还是带有模板参数的模板函数,所以链接的时候就找不对对应需要的实例化模板函数

        关于以上的解决方法,在分离定义中进行显示实例化,如下:

        如上所示,我们可以使用显示实例化来解决这个问题,但是这种问题的解决方法也仅仅只是治标不治本,当我们传入另一个模板实参的时候,还需要显示实例化一次,这并符合模板的特点,所以说,最好将模板的定义和声明放在同一个地方,或者分离定义在同一个文件中。

        另外,关于模板这一块的调用形式很奇怪,一不小心就会用错。所以对于模板的使用,建议将模板的声明和定义放入到同一个文件中(因为在同一个文件中时,既有声明也有定义,直接就实例化,编译的时候,有函数定义,就有函数地址,就不需要等到链接的时候在去寻找

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

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

相关文章

什么是数据中心?关于数据中心的这些知识一定要知道

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。数据中心&#xff0c;作为支撑海量数据存储、处理和分发的基础设施&#xff0c;其战略地位日益凸显。它们不仅是信息技术的心脏&#xff0c;更是推动现代商业决策、创新和运营的核心引擎。随着云计算、大数据、物联网…

React 第三十章 React 和 Vue 描述页面的区别

面试题&#xff1a;React 和 Vue 是如何描述 UI 界面的&#xff1f;有一些什么样的区别&#xff1f; 标准且浅显的回答&#xff1a; React 中使用的是 JSX&#xff0c;Vue 中使用的是模板来描述界面 前端领域经过长期的发展&#xff0c;目前有两种主流的描述 UI 的方案&#xf…

英语学习笔记12——名词所有格的运用

Whose is this … ? This is my/your/his/her … 这……是谁的&#xff1f;这是我的 / 你的 / 他的 / 她的…… Whose is that … ? That is my/your/his/her … 那……是谁的&#xff1f;那是我的 / 你的 / 他的 / 她的…… 词汇 Vocabulary father n. 爸爸 口语&#xf…

ICode国际青少年编程竞赛- Python-6级训练场-多次递归

ICode国际青少年编程竞赛- Python-6级训练场-多次递归 1、 def recur(n):# 边界条件if n<1:return# 额外动作Dev.turnLeft()Dev.step(n)Dev.turnRight()Dev.step(n)Dev.step(-n)Dev.turnRight()Dev.step(2*n)Dev.turnLeft()Dev.step(n)# 递归调用recur(n-1) recur(4)2、 d…

详解xlswriter 操作Excel的高级应用conditional_format

在文章详解xlsxwriter 操作Excel的常用API-CSDN博客 我们介绍了xlswriter 基础api的使用情况&#xff0c;在实际工作中我们经常会遇到下面的需求&#xff0c;cell满足某某条件时&#xff0c;进行对应的格式化处理。这时候我们可以使用conditional_format的函数&#xff0c;他允…

Softing dataFEED OPC Suite通过OPC UA标准加速数字化转型

数字化转型的关键在于成功将信息技术&#xff08;IT&#xff09;与运营技术&#xff08;OT&#xff09;相融合&#xff0c;例如将商业应用程序和服务器与可编程逻辑控制器&#xff08;PLC&#xff09;和设备传感器相融合&#xff0c;为此&#xff0c;各种设备和系统必须能够相互…

ERP系统为何适合电子元件行业?

在快速发展的电子元件行业中&#xff0c;高效、精确的管理系统对于企业的成功至关重要。IC设计ERP系统&#xff0c;作为一套高度集成的企业管理解决方案&#xff0c;其独特的特性和功能使其特别适用于电子元件行业。 首先&#xff0c;ERP系统(Enterprise Resource Planning&…

钽酸锂集成光子芯片:引领光电集成新纪元

在信息技术飞速发展的今天&#xff0c;光电集成技术已成为推动全球集成电路产业持续创新的重要力量。随着全球集成电路产业发展步入“后摩尔时代”&#xff0c;芯片性能提升的难度和成本不断攀升&#xff0c;业界急需寻找新的技术突破口。在这一背景下&#xff0c;中国科学院上…

【深度学习目标检测】二十六、基于深度学习的垃圾检测系统-含数据集、GUI和源码(python,yolov8)

设计垃圾检测系统的意义在于多个方面&#xff0c;这些方面不仅关乎环境保护和城市管理&#xff0c;还涉及到技术进步和社会效益。以下是设计垃圾检测系统的主要意义&#xff1a; 环境保护与资源回收&#xff1a; 垃圾检测系统能够有效地识别不同种类的垃圾&#xff0c;帮助人们…

江苏省人大财经委主任委员谢志成一行莅临聚合数据走访调研

4月18日&#xff0c;江苏省人大财经委主任委员谢志成莅临聚合数据展开考察调研。省人大财经委副主任委员&#xff08;正厅&#xff09;周毅、省人大常委会办公厅一级巡视员吕小鹏、外事委委员赵正驰、省数据局副局长王万军&#xff1b;苏州市人大常委会副秘书长毛元龙、数据局副…

快手二面:你有没有调用过第三方接口?碰到过哪些坑?

在我们的业务开发中&#xff0c;调用第三方接口已经成为常态&#xff0c;比如对接一些ERP系统、WMS系统、一些数据服务系统等&#xff0c;它极大地扩展了我们应用的功能和服务范围。然而&#xff0c;实际对接过程中&#xff0c;我们往往会在这一环节遇到各种意想不到的问题&…

【自动驾驶技术栈学习】1-硬件《大话自动驾驶》| 综述要点总结 by.Akaxi

----------------------------------------------------------------------------------------------------------------- 致谢&#xff1a;感谢十一号线人老师的《大话自动驾驶》书籍&#xff0c;收获颇丰 链接&#xff1a;大话自动驾驶 (豆瓣) (douban.com) -------------…

【科学研究】 女性主义:网络中的性别歧视现象

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

##20 实现图像风格迁移:使用PyTorch深入学习的艺术之旅

文章目录 前言项目概述准备阶段图像处理模型选择风格和内容特征提取风格迁移算法优化过程结果展示完整代码与实验项目结论参考文献 前言 图像风格迁移是一种使一幅图像呈现另一幅画作风格的技术&#xff0c;通过深度学习&#xff0c;我们能够捕捉到内容图像的结构信息和风格图…

函数memcpy的实现及详解

前言 今天我们来了解一下memcpy函数和它的作用吧&#xff0c;咋们之前已经熟悉了strcpy的使用&#xff0c;它的作用是字符串的拷贝&#xff0c;那么当我们要拷贝其他类型的数据时&#xff0c;应该使用什么函数呢&#xff0c;我们今天给大家介绍的就是memcpy函数&#xff0c;他可…

1960—2021年中国月日均温降水时间序列

基于均质级数&#xff08;MASH&#xff09;和气候多元分析方法&#xff0c;首先对1960—2021年中国366个站点的日均气温、最高气温、最低气温和降水量进行不均匀性检测、估计和调整&#xff0c;建立均质化日气温和降水数据集。所有数据集均由希腊&#xff08;帕特雷大学物理系大…

Quests system for Unity

一个简单而灵活的任务系统将帮助你实现所有的想法,而不需要事件和逻辑中的一堆额外代码! 我的资产是一个用于执行任务的独立系统。 特征: 任务逻辑不需要继承MonoBehaviour。 在一行中完成所需任务的激活/进度/完成。 易于理解的界面,包含项目中所有任务的列表。 不需要连接…

【kubeflow文档】kubeflow介绍与架构

1. kubeflow介绍 Kubeflow项目致力于使机器学习&#xff08;ML&#xff09;工作流在Kubernetes上的部署变得简单、可移植和可扩展。目标不是重新创建其他服务&#xff0c;而是提供一种直接的方法&#xff0c;将ML的开源系统部署到不同的基础设施中。无论在哪里运行Kubernetes&a…

Android PreferenceActivity可以自动设置的Activity

1、介绍 PreferenceActivity 是一个抽象类&#xff0c;继承自ListActivity ,该类封装了SharedPreferences. PreferenceActivity 提供了一些常用的设置项如,与普通组件一样&#xff0c;这些配置项既可以从XML文件创建&#xff0c;也可以从代码创建. 每一个设置项标签有一个andro…

在博弈中寻找机会:利用已知信息撬动更多有利信息

在人生的道路上&#xff0c;我们都在参与一场巨大的博弈&#xff0c;无论是职场竞争、商业战争还是人际关系&#xff0c;都需要我们利用已知信息去撬动更多有利的信息&#xff0c;以便在变数中寻找机会。这场博弈既充满挑战&#xff0c;又蕴含着无限可能。 博弈的本质是竞争和合…