博客主页:【夜泉_ly】
本文专栏:【C++】
欢迎点赞收藏⭐关注❤️
在C语言中,
当我们需要为不同类型实现相同逻辑时(如交换两个变量的值),
必须为每个类型编写重复的代码:
void Swap(int& a, int& b) { /*...*/ }
void Swap(double& a, double& b) { /*...*/ }
void Swap(char& a, char& b) { /*...*/ }
这种代码冗余不仅增加维护成本,
也限制了代码的复用性。
C++模板的引入完美解决了这个问题,
让我们能够编写与类型无关的通用代码。
template<typename T>
void Swap(T& x, T& y) {
T tmp = x;
x = y;
y = tmp;
}
template
:声明模板参数
typename
可以和 class
互换,
的作用是完全一致的,T
为类型占位符,在编译时根据实际类型实例化int a = 0, b = 1;
double c = 1.1, d = 2.2;
Swap(a, b); // 生成并调用Swap
Swap(c, d); // 生成并调用Swap
template<typename T>
T* Alloc(int n) {
return new T[n];
}
此时需要显式实例化:
int* arr = Alloc(10);
char* ch = Alloc(10);
模板代码中的类型操作必须适用于所有可能的类型参数。
如:
Date d1(2011,1,1), d2(2000,2,2);
Swap(d1, d2);
Swap
合法的前提是 Date
支持拷贝构造和赋值T tmp = x1; // 调用拷贝构造
x1 = x2; x2 = tmp; // 调用赋值
template<class T>
class Stack {
public:
Stack(size_t capacity = 4);
// ...
private:
T* _array;
size_t _size;
size_t _capacity;
};
在类外定义时,
需要显式地使用模板名来限定作用域:
// 类外定义成员函数
template<class T>
Stack<T>::Stack(size_t capacity) {
// 实现
}
模板函数尽量不要声明和定义分离(不同文件),
有时会出问题。
Stack<int> intStack; // 整型栈
Stack<double> dblStack; // 双精度栈
Stack<char> charStack; // 字符栈
Stack
是模板类型T
变为具体的类型为特定类型提供特殊实现:
template<>
class Stack<bool> { // 针对bool类型的特化实现
public:
// 位压缩存储实现
};
这里有个好玩的:
// 原始模板
template <class T1, class T2 = int> class MyClass {
public:
MyClass() { cout << "1"; }
};
// 全特化
template <> class MyClass<int, int> {
public:
MyClass() { cout << "2"; }
};
int main() {
MyClass<int>();
}
运行结果是 2
对模板参数进行部分约束:
// 原始模板
template<typename T1, typename T2 = int>
class MyClass { /*...*/ };
// 全特化
template<>
class MyClass<int, int> { /*...*/ };
// 指针类型的偏特化
template<typename T>
class MyClass<T*, int> { /*...*/ };
// 引用类型的偏特化
template<typename T>
class MyClass<T&, int> { /*...*/ };
// const类型的偏特化
template<typename T>
class MyClass<const T, int> { /*...*/ };
函数模板的特化中,
函数形参表必须要和函数模板的基础参数类型完全相同,
如果不同编译器可能会报一些奇怪的错误。
template<typename T>
bool Less(const T& left, const T& right) {
return left < right;
}
template<>
bool Less<int*>(int* const& left, int* const& right) {
return *left < *right;
}
特化为 int*
时必须把 const
放在 *
和 &
中间。
错误写法:const int* &left
const T&
const
的 T
的引用int* const&
const
的 int*
的引用const int*&
const int*
的引用类模板的特化同理。
通常情况下,
模板的声明和定义应放在同一个文件中,
尤其是在头文件中。
因为:
解决方案:
在.cpp文件中显式实例化,
告诉编译器为特定类型生成代码
template class Stack<int>;
template class Stack<double>;
如果模板的声明和定义被分开到不同的文件中,
且没有显式实例化,会发生链接错误。
因为示例化的模板并没有生成。
在依赖模板参数的类型前必须使用typename:
template<class T>
void func() {
typename T::const_iterator it; // 告诉编译器这是类型
}
因为 T::const_iterator
可能是个静态成员。
希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!