C++初阶之模板进阶

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶    算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.非类型模板参数

二.模板的特化

2.1引入

2.2全特化

2.3偏特化

三.模板的分离编译

3.1链接错误

3.2链接错误是如何产生的

3.3如何正确分离编译

3.4按需实例化


一.非类型模板参数

        非类型模板参数就是模板的参数有一个常量,我们可以参考下面的代码:

template<class T, size_t N = 10>
class array
{
public :
	T& operator[](size_t index)
	{
		return _arr[index];
	}
	int size()const
	{
		return _size;
	}

private :
	T _arr[N];
	int _size=0;
};

在C++98中我们只支持整形的做为非类型模板参数,在后面的一些版中开始支持其他的类型作为非类型模板参数。在库中我们就有一个类似的设计array这个,我们需要知道这个非常的不好用,因为它实现的功能使用vector就可以实现,而且array在栈上开辟的空间 ,非常容易造成栈溢出,所以可以说这个基本没有任何用处。

二.模板的特化

2.1引入

class Date
{
public:
	friend ostream& operator<<(ostream& _cout, const Date& d);

	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}

template<class T>
bool Less(T left, T right)
{
return left < right;
}
void test1()
{
	cout << Less(1, 2) << endl; // 可以比较,结果正确
	Date d1(2022, 7, 7);
	Date d2(2022, 7, 8);
	cout << Less(d1, d2) << endl; // 可以比较,结果正确
	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << Less(p1, p2) << endl; // 可以比较,结果错误

}

在日期类中我们比较当传入的是值的时候可以比较正确,但是当我i们传入指针时,我们就不能保证这个正确了,这个主要就是比较的是地址,而不是值,因此我们需要特化。

2.2全特化

template<class T>
bool Less(T left, T right)
{
	cout << "Less(T left, T right)" << endl;
	return left < right;
}
template <>
bool Less(Date* left, Date* right)
{
	cout << "Less(Date * left, Date * right)" << endl;
	return *left < *right;
}

        我们需要在已经有的模板上再次写这个模板对它进行特化,但是template后面跟一个尖括号,尖括号里什么也不写,然后将类型写上,再写具体的代码。我们利用上面的代码运行可以看到:

在这里我们比较指针时会走我们的全特化,

2.3偏特化

        偏特化和全特化类似,它只是特化模板的一部分,它就是对参数进一步进行限制,我们可以看下面的代码:

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

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

template <class T1,class T2>
class A<T1*, T2*>
{
public:
	A()
	{
		cout << "A< T1*, T2*>" << endl;
	}
private:
	T1* _al;
	T2* _a2;
};
void test1()
{
	A<int, char> a1;
	A<int, int>a2;
	A<int*, int*>a3;
}

运行结果为

        在类的使用特化时我们需要在已有的类中再次定义这个类,但是类的后面需要加上括号,括号中的内容是类型,原来的类中的template中有几个参数它就有几个参数,特化的内容不同,没有限制的相同,特化的template中的尖括号为没有精准限制的(它不是一个模糊的,不明确的例如int等,但是参数是T*就需要将T写上)。

三.模板的分离编译

3.1链接错误

        我们将一个类进行分离编译,代码如下:

//.h

namespace bit
{
	template<class T, size_t N = 10>
	class array
	{
	public:
		int size() const;
	private:
		T _array[N];
		int _size=0;
	};
}


//.c

namespace bit
{
	template<class T, size_t N >
	int array<T,N>::size() const 
	{
		return _size;
	}
}

我们实例化一次运行可以看到出现了链接错误

链接错误就是找不到地址,我们可以实验一下,只在.h文件中写一个func函数,调用的时候就会出现链接错误,代码如下:

//.h为
void func();
//.c直接调用

这是由于在编译时有这个声明就可以了,连接时才会进行合并call地址,call的地址就是func定义的地方,但是没有定义,所以出现链接错误。 我们将func函数的定义写好后我们看汇编代码

 它会call一下地址。

3.2链接错误是如何产生的

        在编译阶段开始编译器会把模板进行实例化,由于我们是模板的分离编译,所以我们会造成在.h文件中没有定义的地址,.c文件中有定义但是不知道实例化成什么

3.3如何正确分离编译

        我们需要将声明和定义在同一个.h文件中,这样在编译阶段就会实例化,不需要在链接找地址,我们的代码如下:

	template<class T, size_t N = 10>
	class array
	{
	public:
		int size() const;
	private:
		T _array[N];
		int _size=0;
	};

	template<class T, size_t N >
	int array<T, N>::size() const
	{
		return _size;
	}

3.4按需实例化

我们看代码

	template<class T, size_t N = 10>
	class array
	{
	public:
		int size() const;
		void print()
		{
			cout << size(2);
		}
	private:
		T _array[N];
		int _size=0;
	};

	template<class T, size_t N >
	int array<T, N>::size() const
	{
		return _size;
	}

我们可以看到print函数中是错误的,但是我们不适用print这个函数,编译器就不会报错,一旦使用这个就会出错,我们看两个实验:

bit::array<int> a1;
cout<<a1.size();

	bit::array<int> a1;
	a1.print();

造成这个结果的就是因为编译器会进行按需实例化,当我们需要的时候才会进行实例化,随着版本的更新,编译器在很久以前如果里面少写一个分号也可以编译过去,只要我们不去调用。

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

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

相关文章

关于pytest中用例名称使用中文乱码的解决

场景&#xff1a;使用pytest.mark.parametrize装饰器为用例自定义名称时&#xff0c;运行显示乱码。如下图所示&#xff1a; 解决方案&#xff1a; 1.在根目录 pytest.ini中增加一行代码 [pytest] disable_test_id_escaping_and_forfeit_all_rights_to_community_supportTrue…

Point-Nerf 理论笔记和理解

文章目录 什么是point nerf 和Nerf 有什么区别Point Nerf 核心结构有哪些&#xff1f;什么是point-based radiance field? 点云位置以及置信度是怎么来Point pruning 和 Point Growing 什么是point nerf 和Nerf 有什么区别 基本的nerf 是通过过拟合MLP来完成任意视角场景的重…

【CTF Web】CTFShow web6 Writeup(SQL注入+PHP+位运算)

web6 1 阿呆一口老血差点噎死自己&#xff0c;决定杠上了 解法 注意到&#xff1a; <!-- flag in id 1000 -->拦截很多种字符&#xff0c;连 select 也不给用了。 if(preg_match("/\|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|x|hex|\(|\)|\|select/i"…

IOS开发者证书快捷申请

App Uploader 在进行iOS应用开发中,可以借助appuploader辅助工具进行证书制作、上传和安装测试等操作。首先,您需要访问官方网站获取最新版本的appuploader。最新版本已经优化了与Apple账号的登录流程,无需支付688元,并提供了Windows版和Mac版供用户选择。下载完成后,解压…

地质考察AR远程交互展示系统辅助老师日常授课

广东这片充满活力的土地&#xff0c;孕育了一家引领ARVR科技潮流的杰出企业——深圳华锐视点&#xff0c;作为一家专注于VR/AR技术研究与业务开发的先锋公司。多年来&#xff0c;我们不断突破技术壁垒&#xff0c;将AR增强现实技术与各行各业的实际需求完美结合&#xff0c;助力…

【lambdastreammaven】

lambda 匿名函数 为了简化java中的匿名内部类 事件监听 写一个类 实现 ActionListener 接口 (外部类) | | 内部类 类在其他地方用不到, 索性就把这个类定义在类的内部使用 好处: 1.内部可以使用外部类的成员 …

都2024年了!是谁还不会优化 Hive 的小文件啊!!!速看!

文章目录 小文件产生的原因1.查询建表或者插入2.装载数据3.动态分区小文件影响解决方法针对已经存在的小文件进行优化1.小文件归档2.getmerge3.concatenate4.重写针对写入数据时的优化1.调参优化2.动态分区优化3.使用 Spark 算子控制小文件数量查看 HDFS 上的文件时,无意间点进…

已有yarn集群部署spark

已有yarn集群的情况下&#xff0c;部署spark只需要部署客户端。 一、前提条件 已部署yarn集群&#xff0c;部署方式参考&#xff1a;https://blog.csdn.net/weixin_39750084/article/details/136750613?spm1001.2014.3001.5502&#xff0c;我部署的hadoop版本是3.3.6已安装j…

Java的结构与运行机制

1. JDK JRE JVM三者的区别 JDK(Java Development Kit)&#xff1a;Java开发工具包 JDK包含JRE&#xff0c;还包括其他例如&#xff1a;编译器(javac)、javadoc、jar等&#xff0c;JDK是能够创建和编译程序的。 JRE(Java runtime environment)&#xff1a;Java运行环境 JRE是运…

逻辑分析仪 - 采样率/采样深度

采样深度&#xff08;Sampling Depth&#xff09; 采样深度指的是逻辑分析仪在一次捕获过程中可以记录的最大样本数量。简单来说&#xff0c;采样深度越大&#xff0c;逻辑分析仪可以记录的数据量就越多。这对于分析长时间的信号变化或复杂的信号序列非常重要。 采样率&#…

java面试(JVM)

JVM是什么 Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 JVM由哪些部分组成&#xff0c;运行流程是什么 什么是程序计数器 程序计数器…

uniapp微信小程序解决type=“nickname“获取昵称,v-model绑定值为空问题!

解决获取 type"nickname"值为空问题 文章目录 解决获取 type"nickname"值为空问题效果图Demo解决方式通过表单收集内容通过 uni.createSelectorQuery 效果图 开发工具效果图&#xff0c;真机上还会显示键盘输入框 Demo 如果通过 v-model 结合 blur 获取不…

Python数据分析实验四:数据分析综合应用开发

目录 一、实验目的与要求二、主要实验过程1、加载数据集2、数据预处理3、划分数据集4、创建模型估计器5、模型拟合6、模型性能评估 三、主要程序清单和运行结果四、实验体会 一、实验目的与要求 1、目的&#xff1a; 综合运用所学知识&#xff0c;选取有实际背景的应用问题进行…

YOLOv8_pose训练流程-原理解析[关键点检测理论篇]

本篇将介绍一下YOLOv8关键点检测网络的训练流程,同样在看此篇文章之前先去看一下预测流程[YOLOv8_pose预测流程-原理解析[关键点检测理论篇],还有目标检测任务的训练流程YOLOv8训练流程-原理解析[目标检测理论篇] ,这两篇都是前置课程,下图是YOLOv8实例分割的网络结构图。 …

C语言笔记22 •结构体•

C语言结构体 1.结构体类型的声明 struct Stu { char name[ 20 ]; // 名字 int age; // 年龄 char sex[ 5 ]; // 性别 char id[ 20 ]; // 学号 }; 2.结构体变量的创建和初始化 #include <stdio.h>// 定义一个结构体类型 Point struct Point {int x;int y; };i…

pikachu-Unsafe Filedownload

任意点击一个图片进行下载&#xff0c;发现下载的url。 http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filenamekb.png 构造payload&#xff1a; 即可下载 当前页面的源码&#xff0c;可以进行路径穿越来下载一些重要的配置文件来获取信息。 http://127.0.…

【PostgreSQL001】比较开发生产2个数据库结构方法

1.一直以来想写下基于PostgreSQL的系列文章&#xff0c;作为较火的数据ETL工具&#xff0c;也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下PostgreSQL数据库相关知识体系。 3.欢迎批评指正&#xff0c;欢迎关…

【Mac】MWeb Pro(好用的markdown编辑器) v4.5.9中文版安装教程

软件介绍 MWeb Pro for Mac是一款Mac上的Markdown编辑器软件&#xff0c;它支持实时预览&#xff0c;语法高亮&#xff0c;自动保存和备份等功能&#xff0c;并且有多种主题和样式可供选择。此外&#xff0c;MWeb还支持多种导出格式&#xff0c;包括HTML、PDF、Word、ePub等&a…

虚拟机启动Operating System not found找不到操作系统

错误信息 PEX-E51 No SHCP or proxyDHCP offers were received. PXE-M0F: Exiting Intel PXE ROM. Operating System not found解决方法1 到服务里面检查跟vmware相关的服务是否已经全部启动 如果服务怎么都无法启动&#xff0c;最简单的办法还是重装vmware 解决方法2 &#…

数据插值之朗格朗日插值(一)

目录 一、引言 二、代码实现 2.1 Lagrange插值求插值多项式&#xff1a; 代码解析&#xff1a; 1.vpa解释 2.ploy&#xff08;x&#xff09;解释: 3.conv&#xff08;&#xff09;解释 4.poly2sym()解释 2.2 Lagrange插值求新样本值和误差估计&#xff1a; 代码解析&…