C++的模板参数有哪些?
模板(Template):是泛型编程的核心机制,允许在编写代码时使用参数化的类型或值,从而实现代码的复用。模板的参数分为两大类:类型参数和非类型参数,此外还有模板模板参数(较少见)
- 注:博主可没有打错字哦~,名字真的就叫作
模板模板参数啊!
一、类型参数
类型参数(Type Parameters):表示模板中使用的数据类型
- 可以是
内置类型(如:int、double) - 或者是
自定义类型(如:类、结构体)
1. 通用类型参数
使用class或typename声明,两者含义相同(推荐用typename,更清晰)
代码语言:javascript
AI代码解释
template <class T> // 类型参数 T void swap(T& a, T& b) { T temp = a; a = b; b = temp; } template <typename U> // 等价于 class U class Vector { /* ... */ };示例调用:
代码语言:javascript
AI代码解释
swap<int>(3, 5); // 显式指定类型为 int swap<double>(3.14, 2.71); // 显式指定类型为 double // 也可隐式推导类型:swap(3, 5);(编译器自动推导为 int)2. 默认类型参数
可以为类型参数指定默认类型,调用时若未指定则使用默认值
代码语言:javascript
AI代码解释
template <typename T = int> // 默认类型为 int class Stack { // ... }; Stack<> s; // 使用默认类型 int Stack<double> d; // 显式指定类型为 double二、非类型参数
非类型参数(Non-Type Parameters):表示模板中使用的常量值
- 通常为
整型、枚举值或指针/引用 - C++11 后支持
std::nullptr_t、constexpr变量等
1. 基本语法
代码语言:javascript
AI代码解释
template <typename T, int Size> // T 是类型参数,Size 是非类型参数(整数) class Array { private: T data[Size]; // 使用非类型参数 Size 作为数组长度 public: int getSize() const { return Size; } };2. 限制条件
非类型参数必须是编译期可确定的常量,不能是变量或运行时计算的值
代码语言:javascript
AI代码解释
Array<int, 10> arr; // 合法,10 是编译期常量 int n = 10; // Array<int, n> arr; // 非法,n 是变量,非编译期常量对于指针/引用类型的非类型参数,要求其指向的对象具有静态存储期(如:全局变量、static变量)
代码语言:javascript
AI代码解释
int global_var = 0; template <int* ptr> void func() { /* ... */ } func<&global_var>(); // 合法,指向全局变量代码案例:非类型参数的使用小案例
代码语言:javascript
AI代码解释
namespace mySpace { //任务:定义的一个“静态数组”的模板类,同时要使用“非类型参数” template<class T, size_t N = 10> class array { private: T _array[N]; //1.存储数据的静态数组 注意:在编译期确定数组大小 size_t _size; //2.记录数组中有效元素数量的变量 public: //1.实现:“普通版本的下标运算符[]的重载函数” T& operator[](size_t index) //注意:支持对数组元素的读写操作 { return _array[index]; } //2.实现:“const版本的下标运算符[]的重载函数” const T& operator[](size_t index)const //注意:保证在只读场景下也能通过下标访问元素,返回的是 const 引用,确保元素不会被修改 { return _array[index]; } //3.实现:“获取数组中有效元素的数量的操作” size_t size()const { return _size; } //4.实现:“判断数组是否为空的操作” bool empty()const { return _size == 0; } }; }三、模板模板参数
模板模板参数(Template Template Parameters):是指模板本身作为参数,用于将另一个模板传递给当前模板。 (注:暂时先了解一下概念即可)
------------模板特化------------
1. 什么是模板特化?
模板特化(Template Specialization):是模板机制的一个重要特性,允许针对特定的模板参数类型,提供模板的定制化实现。
- 它允许针对特定
类型或值,定制模板的行为,解决通用模板在特殊场景下的 “水土不服” 问题。 - 当模板在某些特定类型下需要不同的行为或更高效的实现时,特化可以让代码更灵活、更贴合需求。
2. 为什么要使用模板特化?
在介绍的模板特化的时候,我们说模板特化是多么的厉害,但是口说无凭,模板特化真的有那么好吗? 下面的我们就来看一看模板特化的重要性。
代码语言:javascript
AI代码解释
#include <iostream> using namespace std; //任务1:定义一个日期类 class Date { public: /*--------------成员变量--------------*/ int _year; int _month; int _day; /*--------------成员函数--------------*/ //1.实现:“默认构造函数” Date(int y, int m, int d) : _year(y) , _month(m) , _day(d) {} //2.实现:“<运算符重载函数” bool operator<(const Date& other) const //注意:用于比较两个日期的先后顺序 { if (_year != other._year) return _year < other._year; // 优先比较年份 if (_month != other._month) return _month < other._month; // 年份相同则比较月份 return _day < other._day; // 年份和月份都相同则比较日期 } }; //任务2:定义比较函数模板 template<class T> bool Less(T x, T y) { return x < y; //注意:依赖 T 类型的 operator< 实现 } int main() { // ---------------- 基础类型比较(正确行为)---------------- // 1. 实例化 Less<int>(int, int) // 调用内置的 int 类型的 < 运算符 cout << Less(1, 2) << endl; // ---------------- 对象类型比较(正确行为)---------------- // 2. 实例化 Less<Date>(Date, Date) // 调用 Date 类重载的 operator< Date d1(2022, 7, 7); Date d2(2022, 7, 8); cout << Less(d1, d2) << endl; // ---------------- 指针类型比较(潜在问题)---------------- // 3. 实例化 Less<Date*>(Date*, Date*) // 调用指针类型的 < 运算符(比较内存地址) Date* p1 = &d1; // p1 指向 d1 的内存地址 Date* p2 = &d2; // p2 指向 d2 的内存地址 cout << Less(p1, p2) << endl; // 可能输出 0 或 1(取决于内存地址的随机分配) //注意:此处本意是比较对象内容,但实际比较的是指针地址 return 0; }在这里插入图片描述
可以看到,
Less函数在大多数情况下都能正常比较,但在特殊场景中会得出错误结果。在上述示例里:
p1指向的d1显然小于p2指向的d2对象- 然而
Less内部并没有比较p1和p2所指向对象的内容 - 而是比较了
p1和p2指针的地址,这就无法达成预期,进而出现错误
(哈哈,虽然博主在自己的VS上演示的结果没有出错,但是并不代表它没有问题呦) 这时,就需要对模板进行特化处理。也就是在原模板的基础上,针对特定类型,进行专门化的实现。
3. 模板特化有哪些?
模板特化的分类:C++ 的模板特化可分为:
函数模板特化和类模板特化两大类。
一、函数模板特化
函数模板特化的步骤
1. 先定义基础函数模板
要特化函数模板,得先有一个通用的基础函数模板,它为各类型提供默认的泛型逻辑。
比如:我们想实现 “比较两个值大小,返回bool结果” 的功能,先写通用模板:
代码语言:javascript
AI代码解释
template <class T> bool Less(T left, T right) { return left < right; }这个模板能处理int、double、自定义类(若重载了<运算符 )等类型的比较,但遇到指针类型时会因比较地址而非内容出问题,这就需要特化。
2. 添加特化声明与实现
- 特化标识:用
template<>表明这是一个模板特化(空尖括号表示不再推导模板参数) - 明确特化类型:在函数名后的尖括号里,写上要专门处理的特定类型(如:
Date*类型,就写Less<Date*>) - 保持形参匹配:特化函数的形参列表,必须和基础函数模板的形参类型严格一致,否则编译器可能报错或匹配异常
前面我们提到,
Less函数在比较p1和p2时,内部并未比较它们所指向对象的内容,而是直接比较了指针的地址,这与预期不符,会导致错误。 此时,需要通过模板特化来解决这一问题。 既然已经了解了模板特化的方法,接下来我们就按照上面的步骤对代码进行特化处理吧!
代码语言:javascript
AI代码解释
#include <iostream> using namespace std; //任务1:定义一个日期类 class Date { public: /*--------------成员变量--------------*/ int _year; int _month; int _day; /*--------------成员函数--------------*/ //1.实现:“默认构造函数” Date(int y, int m, int d) : _year(y) , _month(m) , _day(d) {} //2.实现:“<运算符重载函数” bool operator<(const Date& other) const //注意:用于比较两个日期的先后顺序 { if (_year != other._year) return _year < other._year; // 优先比较年份 if (_month != other._month) return _month < other._month; // 年份相同则比较月份 return _day < other._day; // 年份和月份都相同则比较日期 } }; //任务2:定义比较函数模板Less template<class T> bool Less(T left, T right) { return left < right; //注意:依赖 T 类型的 operator< 实现 } //任务3:对Less函数模板进行特化 template<> bool Less<Date*>(Date* left, Date* right) { return *left < *right; } int main() { // ---------------- 基础类型比较(正确行为)---------------- // 1. 实例化 Less<int>(int, int) // 调用内置的 int 类型的 < 运算符 cout << Less(1, 2) << endl; // ---------------- 对象类型比较(正确行为)---------------- // 2. 实例化 Less<Date>(Date, Date) // 调用 Date 类重载的 operator< Date d1(2022, 7, 7); Date d2(2022, 7, 8); cout << Less(d1, d2) << endl; // ---------------- 指针类型比较(潜在问题)---------------- // 3. 实例化 Less<Date*>(Date*, Date*) // 调用指针类型的 < 运算符(比较内存地址) Date* p1 = &d1; // p1 指向 d1 的内存地址 Date* p2 = &d2; // p2 指向 d2 的内存地址 cout << Less(p1, p2) << endl; //注意:调用特化之后的版本了,而不是走通用模板了 return 0; }在这里插入图片描述
函数模板全特化
函数模板全特化:为函数模板的所有参数显式指定类型,完全覆盖通用逻辑。
语法:
代码语言:javascript
AI代码解释
template <> //函数模板特化 返回类型 模板函数名<特化类型>(参数列表) { ... }示例:通用函数模板用于比较两个值的大小,但对const char*(C 风格字符串),默认会比较指针地址而非内容,所以需要特化:
代码语言:javascript
AI代码解释
#include <iostream> #include <string> using namespace std; /*--------------------- 通用模板(求最大值)---------------------*/ template <typename T> T max_val(T a, T b) { return a > b ? a : b; } /*------------------ 针对const char*类型的全特化 ------------------*/ template <> // 函数模板全特化 const char* max_val<const char*>(const char* a, const char* b) //按字符串字典序比较 { return strcmp(a, b) > 0 ? a : b; // 使用 C 风格字符串比较 //注意:strcmp 返回值:a > b 则 >0,a < b 则 <0,相等则 0 } int main() { /*----------------调用通用模板:比较int值----------------*/ cout << "-----调用通用模板:比较int值-----" << endl; cout << max_val(10, 20) << endl; /*---------------------- 调用全特化版本:比较字符串的内容 ----------------------*/ cout << "-----调用全特化版本:比较字符串的内容-----" << endl; const char* s1 = "apple"; const char* s2 = "banana"; cout << max_val(s1, s2) << endl; //注意:自动匹配特化版本 return 0; }在这里插入图片描述
函数模板偏特化
注意:C++不直接支持
函数模板偏特化(语法会报错),但可通过函数重载模拟类似效果。
- 示例:让
max_val对指针类型,比较指针指向的值,而非指针地址,通过重载实现:指针类型的 “偏特化”
代码语言:javascript
AI代码解释
#include <iostream> using namespace std; // 通用函数模板:比较值 template <class T> T max_val(T a, T b) { return a > b ? a : b; } // 重载版本:针对指针类型(模拟偏特化) template <class T> T* max_val(T* a, T* b) { return *a > *b ? a : b; } int main() { int x = 10, y = 20; // 调用通用模板:比较 int 值 cout << max_val(5, 3) << endl; // 调用重载的指针版本:比较 *x 和 *y int* result = max_val(&x, &y); cout << *result << endl; return 0; }在这里插入图片描述
原理:
- 重载的
max_val(T* a, T* b)并非严格意义的 “偏特化”,但利用函数重载决议,优先匹配指针类型的调用,达到 “针对部分类型定制” 的效果。 - 若直接写函数模板偏特化语法(如:
template <class T> T max_val<T*>(T* a, T* b) { ... }),编译器会报错,因此实际开发常用重载替代。
www.dongchedi.com/article/7597217223819772478
www.dongchedi.com/article/7597215233471889944
www.dongchedi.com/article/7597216873696526910
www.dongchedi.com/article/7597217143041737241
www.dongchedi.com/article/7597214870441935385
www.dongchedi.com/article/7597214599947043353
www.dongchedi.com/article/7597214580846477886
www.dongchedi.com/article/7597216071082738201
www.dongchedi.com/article/7597214433031078424
www.dongchedi.com/article/7597214537498362392
www.dongchedi.com/article/7597215399566361150
www.dongchedi.com/article/7597215658752868888
www.dongchedi.com/article/7597215102077141528
www.dongchedi.com/article/7597214696924004889
www.dongchedi.com/article/7597213042329895448
www.dongchedi.com/article/7597215125493400126
www.dongchedi.com/article/7597212587801018905
www.dongchedi.com/article/7597214580846215742
www.dongchedi.com/article/7597214267869692440
www.dongchedi.com/article/7597213056480969278
www.dongchedi.com/article/7597212812516639257
www.dongchedi.com/article/7597212812516868633
www.dongchedi.com/article/7597213320844182041
www.dongchedi.com/article/7597211160895046206
www.dongchedi.com/article/7597211076186374681
www.dongchedi.com/article/7597212587801477657
www.dongchedi.com/article/7597210839670080062
www.dongchedi.com/article/7597210276412899864
www.dongchedi.com/article/7597211030086926872
www.dongchedi.com/article/7597211160895078974
www.dongchedi.com/article/7597209997126238744
www.dongchedi.com/article/7597209064238039577
www.dongchedi.com/article/7597211030087287320
www.dongchedi.com/article/7597209862904480318
www.dongchedi.com/article/7597209319725253145
www.dongchedi.com/article/7597208525277987353
www.dongchedi.com/article/7597208525278151193
www.dongchedi.com/article/7597210268858958398
www.dongchedi.com/article/7597209475426435609
www.dongchedi.com/article/7597209772429476377
www.dongchedi.com/article/7597201951176213017
www.dongchedi.com/article/7597201687174562366
www.dongchedi.com/article/7597199724889997849
www.dongchedi.com/article/7597199550092657177
www.dongchedi.com/article/7597200248943329816
www.dongchedi.com/article/7597199001863701017
www.dongchedi.com/article/7597198298541834777
www.dongchedi.com/article/7597200591446000190
www.dongchedi.com/article/7597199968348357145
www.dongchedi.com/article/7597199312984162841
www.dongchedi.com/article/7597199429019861566
www.dongchedi.com/article/7597196791863902782
www.dongchedi.com/article/7597197725960110616
www.dongchedi.com/article/7597197533550920217
www.dongchedi.com/article/7597196766895079960
www.dongchedi.com/article/7597197878439756313
www.dongchedi.com/article/7597196909912031768
www.dongchedi.com/article/7597195764053492248
www.dongchedi.com/article/7597196370181030424
www.dongchedi.com/article/7597195961618121241
www.dongchedi.com/article/7597195004385182232
www.dongchedi.com/article/7597196281857442366
www.dongchedi.com/article/7597195368090075673
www.dongchedi.com/article/7597195809683505689
www.dongchedi.com/article/7597194439940932158
www.dongchedi.com/article/7597194164794933822
www.dongchedi.com/article/7597194060553749016
www.dongchedi.com/article/7597195414877995544
www.dongchedi.com/article/7597194911112479256
www.dongchedi.com/article/7597194219174068761
www.dongchedi.com/article/7597192718418756120
www.dongchedi.com/article/7597191743318065689
www.dongchedi.com/article/7597194069471003161
www.dongchedi.com/article/7597193401016500760
www.dongchedi.com/article/7597192147254772286
www.dongchedi.com/article/7597192394672505406
www.dongchedi.com/article/7597190301329080894
www.dongchedi.com/article/7597188998091833881
www.dongchedi.com/article/7597190006675243582
www.dongchedi.com/article/7597189866363372056