【c++】模板详解(2)

news2024/11/26 10:37:34
🌟🌟作者主页:ephemerals__
🌟🌟所属专栏:C++

目录

前言

一、非类型模板参数

二、模板的特化

1. 概念

2. 场景举例

3. 函数模板的特化

4. 类模板的特化

全特化

偏特化

1. 部分特化

2.  对参数的限制

三、模板的分离编译

四、模板优缺点总结

优点

缺点

总结


前言

        之前我们深入探讨了模板的概念、重要性及其在C++编程中的应用:

【c++】模板详解(1)-CSDN博客

通过模板,我们实现了代码的复用,并且初步理解了泛型编程。本篇文章,我们将继续学习模板的相关知识,进一步加深对模板的理解。

一、非类型模板参数

        之前我们在定义模板时,模板参数都是类型,而实际上模板参数可分为类型参数非类型参数,非类形参数在模板实例化时需要被具体的值所替代。通常情况下,非类型参数都是常量表达式。所以在模板当中,我们就可以将非类型参数当作一个常量来使用。

代码示例:

#include <iostream>
using namespace std;

template<class T, size_t N = 10>
class A
{
public:
	size_t size()
	{
		return N;
	}

	//...
private:
	T _arr[N] = { 0 };//创建一个固定大小的数组
};

int main()
{
	A<int> arr;
	cout << arr.size() << endl;
	return 0;
}

这里需要注意:

1. 与类型参数相同,非类型参数可以在参数列表中指定默认值,也可以不指定。但是这个值必须在编译阶段就能确认其结果。例如:

int main()
{
	int a = 5;
	A<int, a> arr1;//编译报错

	A<int, 5> arr2;//正确
	return 0;
}

2. 在c++20之前,非类型参数只能是整形、枚举类型或指针类型的值。c++20之后,才可以使用其他类型的值作为参数。

二、模板的特化

1. 概念

        模板的特化指的是在模板的基础上,我们针对某些特定的类型或值,提供一种特殊的实现方式。当模板被实例化为这种特定类型时,就会根据新的实现方式进行推演,就像是“私人定制”。

2. 场景举例

        例如我们现在要实现一个函数模板,用于通用类型的大小比较:

template<class T>
bool less(T v1, T v2)
{
	return v1 < v2;
}

这种实现方式,对于内置类型和具有比较运算符重载的类类形而言,都可以达到预期效果。但是如果我们传入指针类型呢?

        如果传入指针类型,那么我们的原本期望应该是将两指针指向的数据进行比较,但是该模板推演的结果会将两个指针进行大小比较,是没有意义的。此时我们就可以实现一个针对指针类型的特化版本(只能针对特定指针进行特化)

3. 函数模板的特化

        接下来,我们就针对刚才的例子,写一个特化版本的函数模板:

#include <iostream>
using namespace std;

//基础版本
template<class T>
bool Less(T v1, T v2)
{
	return v1 < v2;
}

//针对指针类型的特化版本
//注意:只能针对特定的指针类型进行特化,这里使用int*
template<>
bool Less<int*>(int* v1, int* v2)
{
	return *v1 < *v2;
}

int main()
{
	int a = 0, b = 1;
	int* pa = &a, * pb = &b;

	cout << Less(pa, pb) << endl;
	return 0;
}

运行结果:

这里要注意以下几点:

1. 函数模板特化时,必须要先有一个基础的函数模板存在。

2. 函数名之前的“template<>”不能省略。

3. 特化版本的函数参数必须和基础版本一一对应(例如该示例当中,基础版本v1、v2的类型都是T,针对int*类型的特化版本中v1、v2的类型都必须是int*),否则会出现编译错误。

        虽然这里的实现方式看起来比较高大上,但了解模板参数匹配原则的小伙伴们都应该知道,我们可以直接实现一个同名函数来解决问题:

bool Less(int* v1, int* v2)
{
	return *v1 < *v2;
}

所以说一般情况下,在函数模板中,我们需要针对特定类型执行特殊操作时,为了保证代码的可读性和简洁性,直接实现一个同名函数即可,不建议特化。相比函数模板的特化,类模板的特化更为常用。

4. 类模板的特化

        类模板的特化可以分为全特化和偏特化。 

全特化

        全特化指的是将模板参数列表中所有的参数都确定下来。 例如:

//基础版本
template<class T1,class T2>
class A
{
public:
	//...
private:
	T1 _a;
	T2 _b;
};

//全特化版本
template<>
class A<int,char>//特化为int、char类型
{
public:
	//...
private:
	int _a;
	char _b;
};

注意:只有当传入的所有模板参数都符合全特化场景时,类模板才会根据全特化版本进行实例化

A<int, int> a;//调用基础版本
A<int, char> a;//调用全特化

偏特化

         偏特化有两种表现形式:

1. 部分特化

        顾名思义,部分特化就是将模板参数中的一部分参数进行特化。例如:

//基础版本
template<class T1,class T2>
class A
{
public:
	//...
private:
	T1 _a;
	T2 _b;
};

//部分特化
template<class T1>//没有特化的部分
class A<T1, int>//将T2特化为int类型
{
public:
	//...
private:
	T1 _a;
	int _b;
};

注意:只要部分特化中特化的参数与传入的模板参数完全匹配,就根据部分特化版本进行实例化。

A<int, double>;//调用基础版本
A<int, int> a;//调用部分特化
2.  对参数的限制

        除了部分特化之外,对参数的某些条件限制也可以称为偏特化。例如:

//基础版本
template<class T1, class T2>
class A
{
public:
	//...
private:
	T1 _a;
	T2 _b;
};

//偏特化为指针类型
template<class T1, class T2>
class A<T1*, T2*>
{
public:
	//...
private:
	T1 _a;
	T2 _b;
};

//偏特化为引用类型
template<class T1, class T2>
class A<T1&, T2&>
{
public:
	A(const T1& a,const T2& b)
		:_a(a)
		,_b(b)
	{}
	//...
private:
	const T1& _a;
	const T2& _b;
};
A<int*, int*> a1; //调用指针偏特化
A<int&, int&> a2(1, 2); //调用引用偏特化

 另外需要注意:当传入的模板参数同时满足全特化和偏特化的条件时,优先选择全特化。

三、模板的分离编译

        首先讲讲什么是分离编译:

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式

之前我们在 “模板详解(1)” 中提到: 声明和定义不应分离到两个文件,否则会出现链接错误。今天我们来探讨一下出现链接错误的原因:

        假设现在有一个函数模板,它的声明和定义分别在头文件和源文件中:

//a.h
template<class T>
T Add(const T& left, const T& right);

//a.cpp
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

//main.cpp
#include"a.h"
int main()
{
	Add(1, 2);
	Add(1.0, 2.0);
	return 0;
}

那么在程序执行之前就会出现这样的情况:

当我们传参之后,源文件中的函数模板并不知道要实例化为什么类型,所以会发生链接错误。

       解决方案:

1. 将声明和定义放在同一头文件当中(推荐)

2. 在定义位置进行显式实例化的声明(不推荐,很不实用) 

四、模板优缺点总结

        最后,我们总结一下c++中模板的优点和缺点:

优点

1. 提高代码复用性:可以在不同的数据类型上生成相同的代码,减少重复代码的编写,提高了代码的可维护性和可读性。
2. 类型安全:模板在编译时会进行类型检查,确保类型的正确。
3. 灵活性:模板可以适应不同的数据类型和数据结构,提供灵活的编程方式。通过特化操作,模板可以针对不同的需求生成特定的代码,满足不同的应用场景。
4. 可扩展性:模板提供了一种扩展C++语言的机制,可以通过在模板中添加特定的功能来扩展语言的能力(如STL),满足了复杂的应用需求。

缺点

1. 编译时间开销:由于模板在编译时需要实例化多个版本,增加编译时间(特别在大型项目中)。
2. 代码膨胀:模板在编译时生成大量代码,这可能会增加可执行文件的体积,占用更多的内存资源。
3. 复杂性:模板代码可能比直接编写的代码更复杂和难以理解。特别是当模板涉及多个参数和复杂的特化时,代码的可读性会降低。
4. 调试困难:由于模板代码在编译时生成,调试时不容易找到到原始模板代码的位置。此外,错误信息凌乱,不易定位错误。

总结

        今天, 我们学习了非类型模板参数、模板特化以及模板分离编译的相关知识,进一步加深了对模板的理解。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

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

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

相关文章

红队笔记--W1R3S、JARBAS、SickOS、Prime打靶练习记录

W1R3S(思路为主) 信息收集 首先使用nmap探测主机&#xff0c;得到192.168.190.147 接下来扫描端口&#xff0c;可以看到ports文件保存了三种格式 其中.nmap和屏幕输出的一样&#xff1b;xml这种的适合机器 nmap -sT --min-rate 10000 -p- 192.168.190.147 -oA nmapscan/ports…

Qt/C++基于重力模拟的像素点水平堆叠效果

本文将深入解析一个基于 Qt/C 的像素点模拟程序。程序通过 重力作用&#xff0c;将随机分布的像素点下落并水平堆叠&#xff0c;同时支持窗口动态拉伸后重新计算像素点分布。 程序功能概述 随机生成像素点&#xff1a;程序在初始化时随机生成一定数量的像素点&#xff0c;每个…

十一月二十五

双向循环链表 class Node:#显性定义出构造函数def __init__(self,data):self.data data #普通节点的数据域self.next None #保存下一个节点的链接域self.prior None #保存前一个节点饿链接域 class DoubleLinkLoop:def __init__(self, node Node):self.head nodeself.siz…

Python + 深度学习从 0 到 1(00 / 99)

希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【深度学习从 0 到 1】谢谢你的支持&#xff01; ⭐ 什么是深度学习&#xff1f; 人工智能、机器学习与…

UG NX二次开发(C++)-UIStyler-指定平面的对象和参数获取

文章目录 1、前言2、在UG NX中创建平面和一个长方体,3、在UI Styler中创建一个UI界面4、在VS中创建一个工程4.1 创建并添加工程文件4.2 在Update_cb方法中添加选择平面的代码4.3 编译完成并测试效果1、前言 在采用NXOpen C++进行二次开发时,采用Menu/UIStyler是一种很常见的…

C# 命令行运行包

环境&#xff1a;net6 nuget包&#xff1a;Cliwrap 3.6.7 program&#xff1a; 相当于cmd运行命令&#xff1a;nuget search json static async Task Main(string[] args) {var cmd Cli.Wrap("D:\\软件\\Nuget\\nuget.exe").WithArguments(args >args.Add("…

长三角文博会:Adobe国际认证体系推动设计人才评价新标准

2024年11月22日&#xff0c;由上海、江苏、浙江、安徽三省一市党委宣传部共同发起的第五届长三角文化博览会&#xff08;简称“长三角文博会”&#xff09;在上海国家会展中心盛大启幕。长三角文博会自2018年起已成功举办多届&#xff0c;已成为展示区域文化产业发展成果、推动…

音视频基础扫盲之视频码率控制策略(CBR、VBR还是ABR)

视频码率控制策略 CBR&#xff08;Constant Bit Rate&#xff09;、VBR&#xff08;Variable Bit Rate&#xff09;和ABR&#xff08;Average Bit Rate&#xff09;是三种常见的比特率控制方式&#xff0c;以视频码率控制为例&#xff0c;视频码率控制策略主要是在保证视频质量…

【C语言】传值调用与传址调用:深度解析与实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;什么是传值调用和传址调用&#xff1f;1. 传值调用&#xff08;Call by Value&#xff09;2. 传址调用&#xff08;Call by Reference&#xff09; &#x1f4af;传值调…

C++《二叉搜索树》

在初阶数据结构中我学习了树基础的概念以及了解了顺序结构的二叉树——堆和链式结构二叉树该如何实现&#xff0c;那么接下来我们将进一步的学习二叉树&#xff0c;在此会先后学习到二叉搜索树、AVL树、红黑树&#xff1b;通过这些的学习将让我们更易于理解后面set、map、哈希等…

Leetcode647. 回文子串(HOT100)

链接 代码&#xff1a; class Solution { public:int countSubstrings(string s) {int res 0;for(int i 0;i<s.size();i){for(int j i,k i;j>0&&k<s.size();j--,k){if(s[j]!s[k])break;else res;}for(int j i,k i1;j>0&&k<s.size();j--…

ubuntu, 安装部署comfyui,记录2:下载模型GGuf及测试

0.清除工作流 1.安装manager 2024年最新ComfyUI汉化及manager插件安装详解&#xff01;_comfyui-manager-CSDN博客 ComfyUI Manager安装 转到ComfyUI的安装目录ComfyUI/custom_nodes; 使用git拉取ComfyUI Manager&#xff0c;git clone https://github.com/ltdrdata/Comf…

【Y20030006】基于php+mysql的课程学习网站的设计与实现(附源码 配置 文档)

网络购物商城的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着互联网的普及和在线教育的兴起&#xff0c;课程学习网站已经成为越来越多人获取知识和提升技能的重要途径。在这样的背景下&#xff0c;开发一个基于Laravel框架的课程学习…

O2O: (BOORL) Bayesian Design Principles for Offline-to-Online RL

ICML 2024 paper code Intro O2O如何避免悲观学习导致sample efficiency较低&#xff0c;亦或者乐观估计导致的performance drop。本文提出贝叶斯准则&#xff0c;指导在线学习过程中的探索和利用。通过构建一个Q值相关的信念分布&#xff0c;agent可以对不同策略的优劣有一个…

Hyper-V配置-cnblog

启用Hyper-V以在 Windows 10上创建虚拟机 &#xff08;1&#xff09;控制面板检查系统要求&#xff1a; 确保您的计算机符合 Hyper-V 的系统要求。通常情况下&#xff0c;您的计算机需要运行 Windows 10 专业版、企业版或教育版&#xff0c;并且具有启用了虚拟化技术的处理器。…

基础免杀 从.rsrc加载shellcode上线

.rsrc 段是PE文件中的一个特定部分&#xff0c;专门用来存储资源数据。这些资源通常包括图标、位图、字符串表、对话框、菜单、版本信息、字体等 具体的shellcode加载方式不在此探讨 在这使用传统的指针执行 WindowsAPI 需要用到如下API FindResource 获取指定资源的信息块…

Excel把其中一张工作表导出成一个新的文件

excel导出一张工作表 一个Excel表里有多个工作表&#xff0c;怎么才能导出一个工作表&#xff0c;让其生成新的Excel文件呢&#xff1f; 第一步&#xff1a;首先打开Excel表格&#xff0c;然后选择要导出的工作表的名字&#xff0c;比如“Sheet1”&#xff0c;把鼠标放到“She…

第四期书生大模型实战营——基础岛第4关-L1G4000-InternLM + LlamaIndex RAG 实践

Tutorial 基础任务 任务要求1&#xff08;必做&#xff0c;参考readme_api.md&#xff09;&#xff1a;基于 LlamaIndex 构建自己的 RAG 知识库&#xff0c;寻找一个问题 A 在使用 LlamaIndex 之前 浦语 API 不会回答&#xff0c;借助 LlamaIndex 后 浦语 API 具备回答 A 的能…

搭建文件服务器并使用Qt实现文件上传和下载(带账号和密码)

文章目录 0 背景1 搭建文件服务器2 代码实现文件上传和下载2.1 在pro文件中添加网络支持2.2 创建网络管理类2.3 文件上传2.4 文件下载 3 扩展&#xff08;其他方法实现文件上传和下载&#xff09;3.1 python3.2 npm3.3 ftp服务器 4 完整的代码 0 背景 因为需要使程序具备在远程…

【初阶数据结构和算法】leetcode刷题之设计循环队列

文章目录 一、实现循环队列1.大致思路分析2.循环队列的结构定义和初始化结构定义初始化 3.循环队列的判空和判满判空和判满难点分析判空判满 4.循环队列的入队列和出队列入队列出队列 5.循环队列取队头和队尾元素取队头元素取队尾元素 6.循环队列的销毁7.最后题解源码 一、实现…