行业知识
【c++】模板进阶
2026-11-07 18:34:09
来源:互联网转载
> 作者���介:დ旧言~,目前大二,现在学习Java,c,c++,Python等
> 座右铭:松树千年终是朽,槿花一日自为荣。
> 目标:了解非类型模板参数,熟练使用模板的特化。
> 毒鸡汤:你活得不快乐的原因是:既无法忍受目前的状态,又没能力改变这一切。
> 望小伙伴们点赞收藏✨加关注哟
前言
早期我们学习了模板,只能说浅学,很多重要的知识点都没有讲解,今天我们来深度讲解模板。
⭐主体
学习模板的进阶我们按照下面的图解来学习:
非类型模板参数
模板参数分为: 类型形参与非类型形参
- 类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称后面
- 非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
类型形参:
// T: 类型模板参数,它是一个类型template class A;
非类型形参:
// T: 类型模板参数,它是一个类型// N: 非类型模板参数,它是一个常量template class A;
实例举例:
#define N 10template // 静态栈class Stack {private:T _a[N];size_t _top;};void test(){Stack st1; // 10Stack st2; // 10} 问题分析:
现在实现了一个静态栈,可以存 10 个数据,实例化的每个对象都可以存 10 个数据,如果我想要第一个对象 st1 存 100 个数据,第二个对象存 200 个数据,这种结构就非常的不好。
问题解决:
此时就需要用到非类型模板参数了
template // 静态栈class Stack {private:T _a[N];size_t _top;};void test(){Stack st1; // 100Stack st2; // 200} 注意事项:
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的
- 非类型的模板参数必须在编译期就能确认结果
(因为模板是在编译阶段就要实例化的,而模板必须要知道实例化成的具体类型之后才能实例化,
因此非类型模板参数和类型模板参数一样,必须在编译阶段就能够确认实例化成的具体类型才可以,
否则编译阶段无法完成实例化,链接阶段就找不到实例化出的具体的类,进而发生链接错误)
模板的特化
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板。
问题探讨
比如:交换两个元素
templatevoid Swap(T& x, T& y){ T tmp(x); x = y; y = tmp;}void test(){ int x = 1, y = 2; Swap(x, y); vector v1 = { 1, 2, 3, 4 }; vector v2 = { 10, 20, 30, 40 }; Swap(v1, v2); // 深拷贝式交换,代价太大,效率低}解决方案一:函数的匹配原则,写一个专门针对 vector 类型对象交换的函数:推荐这种
// 函数匹配原则,专门针对 vector 类型对象交换的函数 -- 推荐这种void Swap(vector& v1, vector& v2){ v1.swap(v2); // 只需要交换对象内部的几个指针即可}解决方案二:函数模板的特化,针对 vector 类型对象的交换进行特殊化处理:
// 函数模板的特化(针对某些具体类型进行特殊化处理) -- 最后还是要经过模板推演templatevoid Swap(vector& v1, vector& v2){ v1.swap(v2);}问题拓展:
此时,就需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化分为:函数模板特化与类模板特化。
函数特化步骤
函数模板的特化步骤:
- 必须要先有一个基础的函数模板。
- 关键字 template 后面接一对空的尖括号
- 函数名后跟一对尖括号 ,尖括号中指定需要特化的类型。
- 函数形参表:必须要和 中指定的类型完全相同,如果不同,编译器可能会报一些奇怪的错误。
小试牛刀:
template // 基础函数模板void add(T1& x, T2& y){cout