目录
- 模板概述
- 函数模板
- 类模板
- 模板特化
- 模板的非类型参数
- 模板的参数化
- 编译时计算与常量表达式
- 示例代码
- 参考资料
1. 模板概述
C++ 中的模板(Template)是实现泛型编程的一个强大特性,它允许开发者编写与类型无关的代码。在编写模板时,函数或类的实现并不依赖于特定的数据类型,而是在编译时由编译器根据实际传入的类型来生成相应的代码。模板支持函数模板和类模板,广泛应用于STL(标准模板库)等库中。
模板有助于提高代码的重用性和灵活性,使得程序能够处理不同类型的输入而不需要重复编写相同的逻辑。
2. 函数模板
函数模板允许你编写一个函数,能够处理不同类型的参数。编译器会根据传入的参数类型自动推导出函数所需的代码。
定义函数模板:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add(3, 4) << endl; // 输出: 7
cout << add(3.5, 4.2) << endl; // 输出: 7.7
return 0;
}
解释:
template <typename T>
定义了一个模板,T
是占位符,代表一个类型。add
函数可以接受任何类型的参数,只要它们是同一类型。- 在
main
函数中,调用add(3, 4)
和add(3.5, 4.2)
时,编译器会自动根据传入的参数类型(int
和double
)推导出正确的模板实例。
3. 类模板
类模板允许你定义一个类,该类可以操作不同类型的数据。类模板的使用与函数模板类似,可以通过传入类型参数来实例化特定类型的类。
定义类模板:
#include <iostream>
using namespace std;
template <typename T>
class Box {
public:
T value;
Box(T v) : value(v) {}
T getValue() {
return value;
}
};
int main() {
Box<int> intBox(10); // 实例化一个 Box 类型为 int 的对象
Box<double> doubleBox(3.14); // 实例化一个 Box 类型为 double 的对象
cout << intBox.getValue() << endl; // 输出: 10
cout << doubleBox.getValue() << endl; // 输出: 3.14
return 0;
}
解释:
Box
是一个类模板,接受一个类型参数T
。- 通过
Box<int>
和Box<double>
来创建不同类型的类实例。 - 类的成员
value
类型根据模板参数T
自动推导。
4. 模板特化
模板特化允许你为特定类型提供模板的自定义实现。模板特化可以分为两种类型:
- 完全特化:为特定类型完全定义一个模板版本。
- 偏特化:为某些特定的模板参数组合提供自定义实现。
完全特化示例:
#include <iostream>
using namespace std;
template <typename T>
T multiply(T a, T b) {
return a * b;
}
// 完全特化 int 类型
template <>
int multiply<int>(int a, int b) {
cout << "Specialized for int" << endl;
return a * b;
}
int main() {
cout << multiply(2.5, 3.5) << endl; // 使用泛型模板
cout << multiply(2, 3) << endl; // 使用完全特化的模板
return 0;
}
解释:
- 为
int
类型提供了一个专门的multiply
实现,这样调用multiply(2, 3)
时会使用特化版本,而不是泛型版本。
5. 模板的非类型参数
模板可以接受除了类型参数外,还可以接受非类型参数(如整数、指针等)。非类型参数在编译时就确定值,可以用来做数组大小或其他编译时常量计算。
非类型模板参数示例:
#include <iostream>
using namespace std;
template <typename T, int size>
class Array {
public:
T arr[size];
void display() {
for (int i = 0; i < size; ++i) {
cout << arr[i] << " ";
}
cout << endl;
}
};
int main() {
Array<int, 5> intArray = {{1, 2, 3, 4, 5}};
intArray.display(); // 输出: 1 2 3 4 5
return 0;
}
解释:
Array
类模板有两个参数:T
类型和size
非类型参数。size
在编译时已经确定,用来指定数组的大小。
6. 模板的参数化
C++11 及以后的版本允许通过 template
参数化模板的类型和非类型参数。这使得模板的应用更加灵活,能够处理更加复杂的类型和数据。
示例:模板参数化
#include <iostream>
using namespace std;
template <typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
return a * b;
}
int main() {
cout << multiply(2, 3.5) << endl; // 输出: 7
return 0;
}
解释:
multiply
函数模板接受两个类型的参数T
和U
,通过decltype(a * b)
自动推导返回类型。
7. 编译时计算与常量表达式
模板可以在编译时进行常量计算,这是通过 constexpr
和模板常量参数来实现的。这使得模板能够在编译期进行更复杂的计算,而不是在运行时。
示例:编译时计算
#include <iostream>
using namespace std;
template <int N>
constexpr int factorial() {
return N * factorial<N - 1>();
}
template <>
constexpr int factorial<0>() {
return 1;
}
int main() {
cout << factorial<5>() << endl; // 输出: 120
return 0;
}
解释:
factorial
模板通过递归实现编译时计算阶乘。- 使用
constexpr
可以在编译时完成计算,避免运行时计算开销。
8. 示例代码
示例 1:函数模板
#include <iostream>
using namespace std;
template <typename T>
T square(T n) {
return n * n;
}
int main() {
cout << square(5) << endl; // 输出: 25
cout << square(3.5) << endl; // 输出: 12.25
return 0;
}
示例 2:类模板
#include <iostream>
using namespace std;
template <typename T>
class Pair {
public:
T first, second;
Pair(T a, T b) : first(a), second(b) {}
void display() {
cout << "First: " << first << ", Second: " << second << endl;
}
};
int main() {
Pair<int> intPair(1, 2);
intPair.display(); // 输出: First: 1, Second: 2
Pair<string> strPair("Hello", "World");
strPair.display(); // 输出: First: Hello, Second: World
return 0;
}
9. 参考资料
总结
C++ 模板是强大的泛型编程工具,可以帮助开发者编写高效、可重用的代码。通过函数模板和类模板,程序员能够创建类型无关的函数和类。在使用模板时,我们可以利用模板特化、非类型参数和参数化等高级特性来进一步优化代码结构和功能。模板广泛应用于 C++ 标准库(如 STL),是 C++ 编程的重要组成部分。
发表回复