C++ 模板进阶

C++ 模板进阶

  • 一.非类型模板参数
    • 1.概念
    • 2.实例
    • 3.注意事项
  • 二.模板的特化
    • 1.引出
    • 2.函数模板的特化
      • 1.语法和使用
      • 2.建议
    • 3.类模板的特化
      • 1.全特化
      • 2.偏特化
        • 1.部分特化
        • 2.对参数进行进一步的限制
    • 4.匹配顺序
  • 三.模板的分离编译
    • 1.什么是分离编译
    • 2.模板的分离编译
    • 3.解决方法
      • 1.显式实例化(不推荐)
      • 2.分离编译放在头文件当中
  • 四.模板的总结

一.非类型模板参数

1.概念

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

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

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

2.实例

比方说我想实现一个静态的栈,栈的大小是10

#define N 10

template<class T>
class Stack
{
private:
	T _arr[N];
};

int main()
{
	Stack<int> st1;

	Stack<string> st2;

	return 0;
}

在这里插入图片描述
可是我需求变了,st1我想要10个大小,st2我想要200个大小,st3我想要1000个大小,st4我想要2个大小…
怎么办?

此时就需要用到非类型模板参数了

template<class T,size_t N>
class Stack
{
private:
	T _arr[N];
};

int main()
{
	Stack<int,10> st1;

	Stack<string,100> st2;

	Stack<char, 1000> st3;

	Stack<int*, 2> st4;

	return 0;
}

在这里插入图片描述
此时你st1想要10个大小,st2想要100个大小,st3想要1000个…
都可以,完美的解决了这个问题

3.注意事项

  1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的
  2. 非类型的模板参数必须在编译期就能确认结果
    (因为模板是在编译阶段就要实例化的,而模板必须要知道实例化成的具体类型之后才能实例化,
    因此非类型模板参数和类型模板参数一样,必须在编译阶段就能够确认实例化成的具体类型才可以,
    否则编译阶段无法完成实例化,链接阶段就找不到实例化出的具体的类,进而发生链接错误)

二.模板的特化

1.引出

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

我们写一个非常简易的日期类,用这个日期类开始下面的介绍
这里给出了头文件,至于源文件就不给大家了,毕竟我们这篇博客的目的也不是实现日期类
关于日期类的完善大家可以看我的这篇博客:
C++类和对象中:运算符重载+const成员函数+日期类的完善
在这里插入图片描述
在这里插入图片描述
对于第三个比较,我们想要比较的其实是p1和p2,可是实际比较的是p1和p2这两个指针
不符合我们的期望,怎么办呢?

2.函数模板的特化

1.语法和使用

在这里插入图片描述
因此我们就可以这样特化

// 函数模板 -- 参数匹配
//基础的函数模板
template<class T>
bool Less(T left, T right)
{
	return left < right;
}
//函数模板的特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
	return *left < *right;
}

在这里插入图片描述
特化之后,如果函数模板的参数跟特化的类型是匹配的,那么就会走特化,并不会走函数的基础模板

跟我们之前学的函数模板推演实例化时如果有更匹配的会优先去匹配那个更匹配的,这个原则是一样的

2.建议

不建议大家使用函数模板的特化,而建议大家直接写一个同名的非函数模板即可,

因为:
1.函数模板的特化和直接写一个同名的非模板函数的工作量是一样的
2.函数模板的特化的要求更多
比如:必须要有一个基础的函数模板
而且函数形参表: 必须要和模板函数的基础参数类型完全相同
3.而且因为const,引用和指针的关系,导致函数模板的特化变得更加复杂
4.直接写一个同名的非函数模板:简单明了,代码的可读性高,容易书写
在这里插入图片描述

3.类模板的特化

1.全特化

全特化: 将模板参数列表中所有的参数都确定化

语法跟函数模板的特化非常相似
都是需要一个基础模板等等…

template<class T1,class T2>
class C
{
public:
	C()
	{
		cout << "C<T1,T2>" << endl;
	}
};

template<>
class C<int,double>
{
public:
	C()
	{
		cout << "C<int,double>" << endl;
	}
};

在这里插入图片描述

2.偏特化

偏特化:任何针对模版参数进一步进行条件限制而设计的特化版本
偏特化有两种表现形式:
部分特化和对参数进行进一步限制

偏特化也要求必须要有基础模板

1.部分特化

比如说特化第一个参数是int

template<class T1,class T2>
class C
{
public:
	C()
	{
		cout << "C<T1,T2>" << endl;
	}
};

template<>
class C<int, double>
{
public:
	C()
	{
		cout << "C<int,double>" << endl;
	}
};

template<class T>
class C<int,T>
{
public:
	C()
	{
		cout << "C<int,T>" << endl;
	}
};

int main()
{
	C<int, double> c1;
	C<int, char> c2;
	C<char, int> c3;
	return 0;
}

在这里插入图片描述

2.对参数进行进一步的限制

偏特化并不仅仅是指特化部分参数,也可以用来对参数进行进一步的限制

针对于我们一开始引入的比较Date*的例子,我们可以使用类模板来解决这个问题

template<class T>
class D
{
public:
	bool less(const T& a, const T& b)
	{
		return a < b;
	}
};

//偏特化一个专门用于指针比较的类
template<class T>
class D<T*>
{
public:
	bool less(const T* a,const T* b)
	{
		return *a < *b;
	}
};
int main()
{
	cout << D<int>().less(2, 1) << endl; // 可以比较,结果正确
	Date d1(2024, 8, 5);
	Date d2(2024, 8, 10);
	cout << D<Date>().less(d1, d2) << endl; // 可以比较,结果正确
	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << D<Date*>().less(p1, p2) << endl; // 可以比较,结果正确
	return 0;
}

在这里插入图片描述
在这里插入图片描述
注意:这里不建议在偏特化指针类型时加上&

bool less(const T* const& a,const T*& b)

因为如果加上了&,就容易出现这种错误
在这里插入图片描述
此时只需要在引用前面加上const即可

bool less(const T* const& a,const T* const& b)

在这里插入图片描述

4.匹配顺序

模板参数的匹配原则:
会优先匹配更匹配的

如果跟全特化匹配,就匹配全特化
否则如果跟偏特化更匹配,就匹配偏特化
如果跟偏特化也不匹配,就匹配原模板

三.模板的分离编译

1.什么是分离编译

在这里插入图片描述

2.模板的分离编译

我们知道一般的类或者函数都是可以分离编译的,
短小,简单的函数定义为内联函数放在头文件当中
其他函数仅仅将声明放在头文件,定义放在源文件当中

对于带有模板的类或者函数,支持分离编译吗?

下面我们以函数模板为例,演示一下:
例如下面这份程序,对非模板函数f1和模板函数f2进行了分离编译
在这里插入图片描述
一编译,结果发现连接错误,原因是找不到模板函数f2的地址
在这里插入图片描述
为什么会这样呢?
下面我们来分析一下
首先,经过之前的学习,我们知道:
在这里插入图片描述
今天我们需要留意的是:
在这里插入图片描述
因此我们可以得出如下结论:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.解决方法

1.显式实例化(不推荐)

在定义该函数的源文件当中进行显式实例化

func.cpp
//显式实例化
template
void f2<int>(const int& a);

//f2的定义
template<class T>
void f2(const T& a)
{
	cout << "f2<T>" << endl;
}

在这里插入图片描述
不过这种方法并不好用,甚至非常难用
比如,我现在不想f2(1)这么调用了
我想f2(1.1)这么调用,让T实例化为double
此时又链接错误了…
在这里插入图片描述

2.分离编译放在头文件当中

那么怎么办呢?
要不然干脆不进行声明跟定义分离,这样当然可以
要不然声明跟定义分离,但是将定义也放在头文件当中
这样的话,用声明的地方一定有定义
编译阶段就能够正常实例化出模板参数的类型了

通常情况下,这种包含模板的头文件习惯性命名为.hpp文件
当然命名为.h文件也是可以的
在这里插入图片描述
这种时候你想怎么玩就怎么玩

四.模板的总结

在这里插入图片描述

以上就是C++ 模板进阶的全部内容,希望能对大家有所帮助!

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

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

相关文章

C++中的拷贝构造函数

一、拷贝构造函数的概念 拷贝构造函数用于创建一个与已有对象相同的对象&#xff0c;本质上也是构造函数的重载 拷贝构造函数只有一个类型为 const 类类型引用的形参&#xff0c;当我们要创建一个与已存在对象相同的对象时&#xff0c;由编译器自动调用拷贝构造函数。 clas…

MySQL运行错误:‘mysql‘不是内部或外部命令,也不是可运行程序或批处理文

主要原因是&#xff1a;没有将mysql安装目录下的bin目录&#xff0c;添加到系统变量中 编辑系统环境变量 双击Path即可 下一步 记得每一步点击确定就好啦。 下面验证一下是否成功呢&#xff1f; 输入命令符(V是大写的哦~&#xff09; mysql -V 以上就是成功啦&#xff01…

Flink理论—容错之状态

Flink理论—容错之状态 在 Flink 的框架中&#xff0c;进行有状态的计算是 Flink 最重要的特性之一。所谓的状态&#xff0c;其实指的是 Flink 程序的中间计算结果。Flink 支持了不同类型的状态&#xff0c;并且针对状态的持久化还提供了专门的机制和状态管理器。 Flink 使用…

一周学会Django5 Python Web开发-项目配置settings.py文件-模版配置

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计17条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

OpenAI突然发布首款文生视频模型——Sora;谷歌发布Gemini 1.5,迈向多模态大模型新时代

&#x1f989; AI新闻 &#x1f680; OpenAI突然发布首款文生视频模型——Sora 摘要&#xff1a;OpenAI发布了首个AI视频模型Sora&#xff0c;可以根据文字指令生成神级效果的长视频&#xff0c;引发了广泛关注和震惊。 Sora模型通过深入理解语言和图像&#xff0c;能够创造出…

阿里云香港服务器多少钱一年?288元

阿里云香港服务器2核1G、30M带宽、40GB ESSD系统盘优惠价格24元/月&#xff0c;288元一年&#xff0c;每月流量1024GB&#xff0c;多配置可选&#xff0c;官方优惠活动入口 https://t.aliyun.com/U/bLynLC 阿里云服务器网aliyunfuwuqi.com分享阿里云香港服务器优惠活动、详细配…

前端工程化面试题 | 10.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【算法设计与分析】搜索旋转排序数组

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff…

Covalent Network(CQT)与卡尔加里大学建立合作,共同推动区块链技术创新

Covalent Network&#xff08;CQT&#xff09;作为领先的 Web3 数据索引器和提供者&#xff0c;宣布已经与卡尔加里大学达成了具备开创性意义的合作&#xff0c;此次合作标志着推动区块链数据研究和可访问性的重要里程碑。卡尔加里大学是首个以验证者的身份加入 Covalent Netwo…

程序全家桶 | 机器学习之心【Python机器学习/深度学习程序全家桶】

理论背景 机器学习&#xff08;Machine Learning&#xff09;是一种人工智能&#xff08;Artificial Intelligence&#xff09;领域的技术和方法&#xff0c;通过使用数据和统计模型&#xff0c;使计算机系统能够自动学习和改进&#xff0c;而无需明确地进行编程。机器学习使计…

RUST入门:如何用vscode调试rust程序

RUST已经流行一阵子了&#xff0c;但是比较系统的IDE介绍还是比较少&#xff0c;这里我简单介绍 一下如何用vscode实现单步调试rust程序&#xff0c;就像我们平时调试c程序一样。 学习资料网站 首先&#xff0c;介绍几个学习rust的好网站&#xff0c; Rust程序设计语言Rust语…

html从零开始8:css3新特性、动画、媒体查询、雪碧图、字体图标【搬代码】

css3新特性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, …

分布式事务详解

概述 随着互联网的发展,软件系统由原来的单体应用转变为分布式应用。分布式系统把一个单体应用拆分为可独立部署的多个服务,因此需要服务与服务之间远程协作才能完成事务操作。这种分布式系统下不同服务之间通过远程协作完成的事务称之为分布式事务,例如用户注册送积分事务…

一、部署Oracle

部署Oracle 一、Docker部署1.Oracle11g1.1 测试环境1.1.1 拉取镜像1.1.2 启动容器1.1.3 配置容器环境变量1.1.4 修改sys、system用户密码1.1.5 创建表空间1.1.6 创建用户并授权1.1.5 使用DBeaver测试连接 二、安装包部署 一、Docker部署 1.Oracle11g 1.1 测试环境 当前只能用…

MATLAB知识点:perms函数(★★★☆☆)用来返回向量v中各元素所有可能的排列情况

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第三…

适用于电脑和手机的照片恢复工具指南

这是适用于 Android、iPhone、Mac 和 Windows 的最佳照片恢复应用程序的指南。 如果您不小心删除了一堆珍贵的照片&#xff0c;请不要担心&#xff01; 恢复丢失的照片和数据实际上比您想象的要容易得多。 通过使用照片恢复应用程序&#xff0c;您可以“解锁”存储卡或硬盘驱…

OpenCV Mat实例详解 四

OpenCV Mat实例详解三中详细介绍来了OpenCV Mat类的公有静态成员函数&#xff0c;下面介绍OpenCV Mat类的其他常用成员函数。 OpenCV Mat类常用成员函数 Mat & adjustROI (int dtop, int dbottom, int dleft, int dright)&#xff1b; dtop ROI 上边界移动值&#xff0c;如…

BUGKU-WEB game1

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 是一个盖楼的游戏&#xff01; 解题思路 先看看源码&#xff0c;好像没发现什么特别的是不是要得到一定的分数才会有对应的flag&#xff1f;查看下F12&#xff0c;请求链接发现&#xff0c;这不就提示了 相…

[计算机网络]---序列化和反序列化

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、再谈协议…

C++动态规划-线性dp算法

莫愁千里路 自有到来风 CSDN 请求进入专栏 X 是否进入《C专栏》? 确定 目录 线性dp简介 斐波那契数列模型 第N个泰波那契数 思路&#xff1a; 代码测试&#xff1a; 三步问题 思路&#xff1a; 代码测试&#xff1a; 最小花费爬楼梯 思路…