C++模板进阶及特化实战指南
一、非类型模板参数
模板参数分为:

类型模板形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型模板形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
在前面的学习中,我们已经学习类型模板参数,接下来我们一起来看一下非类型模板参数。
在我们现阶段的学习中,非类型模板参数就是指传的是常量(现阶段只能传整型int)
假设现在我想搞一个静态的栈,按照以前的逻辑,我们是不是可以搞个宏——
代码语言:javascript
AI代码解释
#define N=10
template<class T>
class Stack
{
private:
T _a[N];
int _top;
};
代码语言:javascript
AI代码解释
void test1()
{
stack<int> st;//存储10个数据
stack<int> st1;//存储1000个数据
}
那如果我想存储1000个数据,那是不是就要N=1000,那st中就会有空间浪费
这时候,非类型模板参数就闪亮登场~~~
代码语言:javascript
AI代码解释
namespace carrot
{
template<class T ,size_t N=10>非类型模板参数可以给缺省值
class Stack
{
public:
Stack()
:_a(new T[n])
{}
private:
T _a[N];
int _top;
};
void test1()
{
Stack<int, 10> st1;//存储10个数据的静态栈
Stack<int, 1000> st1;//存储1000个数据的静态栈
}
}

注意:C++20才开始支持double,int* ,现在只支持整型!!!
注意:
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
- 非类型的模板参数必须在编译期就能确认结果。
1.1 array——非类型模板参数的应用
ok,接下来我们就来介绍一下array——

array是一个静态数组,它的底层使用了非类型模板参数,然后用这个非类型模板参数定义的数组。
1.1.1 常用接口

我们看到array的接口和前面我们所学容器的接口没有啥区别,唯一的区别就是:array不支持头插、尾插以及中间插入(这是因为空间已经开好了,无法进行扩容操作)
我们看到array是一个静态数组,那array和 int a[10] 有啥区别呢?array是封装的,而a不是封装的。
这里还有个一个问题:array支持的,数组a也支持啊, 那为什么要有array?
- 我们可以更好的用这种类型(array),开空间更快,编译时给空间
代码语言:javascript
AI代码解释
//假如现在我想在一个链表中中的每个节点中存一个数组,用array就很方便
list<array<int, 10>> lt;
- 传参数,数组传参是传指针,在函数的内部不能使用范围for,而array是引用传参。

如果数组想在函数中使用范围for,就要将数组的大小传进去。
除此之外,普通数组也可以使用sort,指向数组的指针是天然的迭代器!!!
总结:再去做其他容器类型,或者进行传参时,array都有普通数组达不到的优势!!!
在前面的学习中,我们了解到:数组越界是会检查的,但是这种检查是抽查,靠近临近位置可以查出来——

但是,这些问题对于array来说,简直就是小意思~
因为array是运算符重载调用,内存严格检查!!!
二、模板的定制能力:针对特定类型的特化实现
2.1 概念
所谓“特化”,其实就是特殊化处理
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)