C++ 模板初阶

news2025/1/17 14:03:11

目录

一、函数模板

1.函数模板的概念

2.函数模板的定义

3.函数模板的原理

4.函数模板的实例化

①隐式实例化

②显式实例化

5.非模板函数与同名的函数模板同时存在

6.模板参数的匹配原则

二、类模板

1.类模板的定义格式

2.采用类模板的类外函数的定义格式

3.类模板的使用(以顺序表[部分功能]为例)

4.类模板的实例化


一、函数模板

1.函数模板的概念

  1. 函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能
  2. 函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
template<typename T>
T Add(T a, T b) {
    return a + b;
}

2.函数模板的定义

template<typename T1, typename T2,…,typename Tn>

注意: typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class) 

示例如下:

//...
void swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

//...
int a = 10;
int b = 20;
swap(a, b);
std::cout << a << " " << b << std::endl;

double c = 1.6;
double d = 2.4;
swap(c, d);
std::cout << c << " " << d << std::endl;

char e = 'a';
char f = 'b';
swap(e, f);
std::cout << e << " " << f << std::endl;

结果:

20 10
2.6 1.2
b a

3.函数模板的原理

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

4.函数模板的实例化

函数模板实例化是指在使用函数模板时,将其具体化为一个实际的函数。在函数模板的定义中,我们使用了一些通用的类型或值作为函数参数,这些类型或值在函数被调用时才被具体指定,从而形成实际的函数。

函数模板参数实例化可以分为两种方式:隐式实例化显式实例化

①隐式实例化

隐式实例化:一种让编译器根据函数模板调用时的实参类型来推导模板参数类型的机制。 

注:隐式类型转换和强制类型转换不会改变原有的类型,只是生成了一个临时变量。

代码如下:

template<class T>
void print(const T& input)
{
	std::cout << input << std::endl;
}
int main()
{
	print(42);
	print("Hello World!");
	return 0;
}

输出:

42
Hello World!

由于模板实例化,所以不同参数类型所调用函数的地址各不同。

②显式实例化

显式实例化:代码中显式地要求编译器实例化某个函数模板的特定实例。

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	std::cout << Add(1, 2) << std::endl;
	std::cout << Add<int>(1, 2.2) << std::endl;     //2.2被隐式类型转换为2
	std::cout << Add<int>(1, "123") << std::endl;	//"123"无法被隐式转换,会直接报错
	return 0;
}

5.非模板函数与同名的函数模板同时存在

对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	std::cout << Add(1, 2) << std::endl;      // 与非模板函数匹配,编译器不需要特化
	std::cout << Add<int>(1, 2) << std::endl; // 调用编译器特化模板的Add版本
    Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
int main()
{
	Test();
	return 0;
}

6.模板参数的匹配原则

  1. 精确匹配:如果实参类型与模板参数类型相同,则精确匹配成功。

  2. 隐式转换匹配:如果实参类型可以隐式转换为模板参数类型,则匹配成功。具体而言,如果实参类型与模板参数类型之间存在以下一种或多种转换关系,则匹配成功:

    • 数组或函数类型指针可以转换为相应的指针类型。

    • 派生类指针可以转换为基类指针。

    • 除非模板参数是引用类型,否则指针或整数类型可以相互转换。

    • 枚举类型可以转换为整数类型,反之亦然。

    • 单精度浮点类型可以转换为双精度浮点类型,反之亦然。

    • 实参类型可以通过用户定义的类型转换函数转换为模板参数类型。

  3. 非类型模板参数匹配:如果模板参数是一个非类型参数(例如整数常量),则实参可以是一个常量表达式,其值可以在编译时计算得出,并且与模板参数类型匹配。

二、类模板

1.类模板的定义格式

template<class T1, class T2, …, class Tn>
class 类模板名
{
// 类内成员定义和声明
};

2.采用类模板的类外函数的定义格式

template<class T1, class T2, …, class Tn>
返回类型 类模板名<T1, T2, …, Tn>::函数名称(参数)
{
// 类外函数的定义
}

3.类模板的使用(以顺序表[部分功能]为例)

template<class T>
class SeqList
{
public:
	SeqList(size_t capacity = 10)
		: _capacity(capacity)
		, _size(0)
		, _array(new T[capacity])
	{}

	// [fist, last]区间中包含的元素要放置到顺序表中
	SeqList(T* first, T* last);

	~SeqList();
	void PushBack(const T& x);
	void PopBack();

	size_t Capacity() const;
	size_t Size() const;

private:
	void CheckFull()
	{
		if (_size == _capacity && _capacity != 0)
		{
			T* tmp = new T[_capacity * 2];
			memcpy(tmp, _array, sizeof(T) * _capacity);
			delete[](_array);
			_array = tmp;
			_capacity *= 2;
		}
	}
	bool CheckEmpty() const
	{
		return _size == 0;
	}
private:
	size_t _capacity;
	size_t _size;
	T* _array;
};

template<class T>
SeqList<T>::SeqList(T* first, T* last)
{
	T* it = first;
	size_t count = 0;
	while (it++ != last + 1) count++;
	_size = count;
	_capacity = count;
	_array = new T[_capacity];
	for (int i = 0; i < _size; ++i)
	{
		_array[i] = *(first++);
	}
}

template<class T>
SeqList<T>::~SeqList()
{
	if (_array)
	{
		delete[] _array;
		_array = nullptr;
		_size = 0;
		_capacity = 0;
	}
}

template<class T>
void SeqList<T>::PushBack(const T& x)
{
	CheckFull();
	_array[_size++] = x;
}

template<class T>
void SeqList<T>::PopBack()
{
	if (CheckEmpty())
	{
		std::cout << "The SeqList is empty!" << std::endl;
		return;
	}
	_size--;
}

template<class T>
size_t SeqList<T>::Capacity() const
{
	return _capacity;
}

template<class T>
size_t SeqList<T>::Size() const
{
	return _size;
}
int main()
{
	int a[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	SeqList<int> s1(&a[0], &a[9]);

	std::cout << s1.Capacity() << std::endl;
	std::cout << s1.Size() << std::endl;

	s1.PushBack(1);
	s1.PushBack(1);
	s1.PushBack(1);

	s1.PopBack();

	std::cout << s1.Capacity() << std::endl;
	std::cout << s1.Size() << std::endl;
	return 0;
}

 输出:

10
10
20
12

4.类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

// Vector类名,Vector才是类型
Vector s1;
Vector s2;

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

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

相关文章

【Linux-计算机网络】-TCP协议通信流程

1.TCP协议通信流程图 1.1TCP协议的通讯流程可以分为以下步骤&#xff1a; 应用层&#xff1a;应用程序通过系统调用API&#xff08;如socket&#xff09;创建一个TCP套接字&#xff08;socket&#xff09;&#xff0c;并设置好相关的选项。 传输层&#xff1a;当应用程序调用c…

机器学习中的数学原理——过拟合、正则化与惩罚函数

通过这篇博客&#xff0c;你将清晰的明白什么是过拟合、正则化、惩罚函数。这个专栏名为白话机器学习中数学学习笔记&#xff0c;主要是用来分享一下我在 机器学习中的学习笔记及一些感悟&#xff0c;也希望对你的学习有帮助哦&#xff01;感兴趣的小伙伴欢迎私信或者评论区留言…

153.网络安全渗透测试—[Cobalt Strike系列]—[生成hta/exe/宏后门]

我认为&#xff0c;无论是学习安全还是从事安全的人多多少少都会有些许的情怀和使命感&#xff01;&#xff01;&#xff01; 文章目录一、后门简介1、hta后门2、exe后门3、宏病毒后门二、生成后门并测试0、测试环境1、生成hta后门并测试2、生成exe后门并测试3、生成宏病毒后门…

分布式监控平台-Zabbix

分布监控平台-Zabbix一、Zabbix概述1、Zabbix是什么&#xff1f;2、Zabbix监控原理二、部署Zabbix服务端&#xff08;端口&#xff1a;10051&#xff09;1、关闭防火墙 修改主机名2、获取Zabbix下载资源3、安装SCL(Software Collections)&#xff0c;修改 Zabbix-front 前端源4…

SQL Server的子查询

SQL Server的子查询一、子查询基础知识二、子查询规则三、限定子查询中的列名四、子查询的多层嵌套五、相关子查询六、子查询类型总结一、子查询基础知识 子查询是嵌套在SELECT、INSERT、UPDATE、DELETE语句中或另一个子查询中的查询。 可以在允许表达式的任何位置使用子查询。…

【MySQL】联合查询

目录 1、前言 2、联合查询 3、内连接和外连接 4、案例演示 4.1 查询篮球哥每科的成绩 4.2 查询所有同学的总成绩及邮箱 5、自连接 5.1 显示所有计算机原理成绩比java成绩高的同学 6、子查询 6.1 查询出篮球哥的同班同学 6.2 多行子查询 7、合并查询 1、前言 在实际…

macOS Monterey 12.6.5 (21G531) 正式版发布,ISO、IPSW、PKG 下载

本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 2023 年 4 月 10 日&#xff08;北京…

如何使用Midjourney辅助建筑平面设计和室内设计,常用的建筑平面效果图提示和使用效果展示(内附Midjourney提示词网站)

文章目录一、室内建筑平面设计1.AutoCAD图纸&#xff08;别墅图为例&#xff09;2.平面效果图3.三维平面透视图二、建筑室内设计1.现代简约2.波西米亚风格3.工业风格4.沿海风格5.法国风格6.现代风格7.提示增加颜色倾向8.提示中增加设计师9.其它一些尝试三、好用的Midjourney提示…

unity 全局光照

全局光照由两部分组成&#xff1a;直接光照和间接光照。 直接光照由直接光照射到物体上以后直接弹射到人眼接收到的光照。 间接光照为直接光照照射到物体上又弹射到其它物体上面以后多次弹射才被人眼接收的光照&#xff08;两次及以上的光照统称为间接光照&#xff09; 材质光…

消息队列RocketMQ、Kafka小计

1、消息队列模型 点对点模式 &#xff08;一对一&#xff0c;消费者主动拉取数据&#xff0c;消息收到后消息清除&#xff09;点对点模型通常是一个基于拉取或者轮询的消息传送模型&#xff0c;这种模型从队列中请求信息&#xff0c;而不是将消息推送到客户端。这个模型的特点是…

Observability: Elastic RUM (真实用户监控)演示

在之前的文章 “Elastic RUM&#xff08;真实用户监测&#xff09;浅谈”&#xff0c;我们详细描述了 Elastic RUM &#xff08;Real User Monitor&#xff09;。在今天的文章中&#xff0c;我将详细一步一步地对该文章进行演示以便大家也能和我一样进行展示。在今天的展示中&a…

Docker6种网络配置详解,网络模式应该这么选

文章目录一、Bridge网络模式二、Host网络模式三、Overlay网络模式四、None网络模式五、Macvlan网络模式六、Ipvlan网络模式七、网络模式选择在Docker中&#xff0c;网络配置是一个重要的主题&#xff0c;因为容器需要与其他容器或外部网络进行通信。Docker提供了多种网络模式和…

GPT-4 和ChatGPT API的定价分析

OpenAI发布了他们的ChatGPT新机器学习模型GPT-4。GPT-4是GPT-3的一大进步&#xff0c;GPT-3是当前ChatGPT免费版本(GPT 3.5 Turbo)所运行的模型的基础&#xff0c;今天我们也来凑个热点&#xff0c;研究一下它们的定价 GPT-4新的功能 GPT-4可以在对话中使用图像&#xff0c;并…

2023年美赛春季赛 赛题浅析

由于今年各种各样的原因&#xff0c;导致美赛头一次&#xff0c;据说也将是最后一次&#xff0c;临时调整&#xff0c;加设春季赛。这对于急需建模奖项的大家来说是一个很好的机会。无论怎样的原因&#xff0c;今年美赛我们可能有所遗憾。但&#xff0c;春季赛也许就是弥补遗憾…

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…

Linux之磁盘分区、挂载

文章目录一、Linux分区●原理介绍●硬盘说明查看所有设备挂载情况挂载的经典案例二、磁盘情况查询基本语法应用实例磁盘情况-工作实用指令一、Linux分区 ●原理介绍 Linux来说无论有几个分区&#xff0c;分给哪一目录使用&#xff0c;它归根结底就只有一个根目录&#xff0c;…

【软考五】数据库(做题)

该文章不适合学习数据库&#xff0c;适合考证&#xff0c;遇到实际问题的&#xff0c;不要在这儿浪费时间。切记切记 软考之数据库一、概念数据模型&#xff08;下午题常考&#xff09;二、结构数据模型关系模型1、关系模型中基本术语2、关系模型中的关系完整性约束3、关系代数…

SQL Server 数据查询

文章目录前言首先在SQL Server 2008 中新建一个数据库chaxun.在库中建三个表,结构如下表所示,并且录入数据.1.2.(1)在KC表中查询学分低于三分的课程信息&#xff0c;并按课程号升序排列(2)在XS_KC表中按学号分组汇总学生的平均分&#xff0c;并按平均分的降序排列(3)在XS_KC表中…

「文心一言」内测详细使用体验

★观前提示&#xff1a;以下内容仅为内测测试内容&#xff0c;不代表未来正式版如何&#xff0c;或许你认为它与chatgpt仍有不小的差距&#xff0c;或许你认为它目前做的已经不错了&#xff0c;都可以&#xff0c;但是咱们测试体验&#xff0c;只讲述体验&#xff0c;本篇文章不…

【数字图像处理】直方图均衡化

文章目录1. 算法原理2. 算法缺陷及改进2.1 缺陷2.2 改进3. 实现3.1 调包侠版本3.2 自由发挥版本1. 算法原理 直方图均衡化是一种常见的图像增强方法&#xff0c;可以增强图像的对比度。其数学原理如下&#xff1a; 首先&#xff0c;我们需要了解直方图的概念。直方图是对图像…