函数模板(Function Template)是 C++ 中实现泛型编程的核心工具,它允许编写与类型无关的通用代码。通过函数模板,你可以定义一个函数蓝图,编译器会根据实际使用的类型自动生成具体的函数代码。
基本概念
1. 模板定义
// 定义一个函数模板
template <typename T>
// T 是类型参数
T {
(a > b) ? a : b;
}
< >
{
(a < b) ? a : b;
}
C++ 函数模板是泛型编程的核心工具,允许编写与类型无关的通用代码。模板定义、使用方式、参数(类型与非类型)、实例化(隐式与显式)、重载机制及特化方法。通过 swap、findMax、bubbleSort 等实战示例展示了模板的应用。同时涵盖了最佳实践,如将模板定义放在头文件、使用 C++20 概念约束以及避免代码膨胀。函数模板提高了代码复用性,是 STL 的基石。
函数模板(Function Template)是 C++ 中实现泛型编程的核心工具,它允许编写与类型无关的通用代码。通过函数模板,你可以定义一个函数蓝图,编译器会根据实际使用的类型自动生成具体的函数代码。
// 定义一个函数模板
template <typename T>
// T 是类型参数
T {
(a > b) ? a : b;
}
< >
{
(a < b) ? a : b;
}
int main() {
int i1 = 10, i2 = 20;
double d1 = 3.14, d2 = 2.71;
char c1 = 'A', c2 = 'B';
// 编译器自动推导类型并生成具体函数
cout << max(i1, i2) << endl; // 生成 max<int>(int, int)
cout << max(d1, d2) << endl; // 生成 max<double>(double, double)
cout << max(c1, c2) << endl; // 生成 max<char>(char, char)
return 0;
}
// 单个类型参数
template <typename T>
void print(T value) {
cout << value << endl;
}
// 多个类型参数
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
// 使用 print(42); // T = int
// print("Hello"); // T = const char*
// add(3, 4.5); // T1 = int, T2 = double
模板参数也可以是值(整数、指针、引用等):
// 数组大小作为模板参数
template <typename T, int size>
class FixedArray {
private:
T data[size];
public:
T& operator[](int index) {
return data[index];
}
};
// 使用 FixedArray<int, 10> arr; // 创建包含 10 个 int 的数组
// 函数模板中的非类型参数
template <typename T, int N>
void fillArray(T (&arr)[N], T value) {
for (int i = 0; i < N; i++) {
arr[i] = value;
}
}
编译器根据调用自动推导类型:
template <typename T>
T square(T x) {
return x * x;
}
int main() {
square(5); // 实例化为 square<int>(int)
square(3.14); // 实例化为 square<double>(double)
return 0;
}
明确指定模板参数:
template <typename T>
void process(T data) {
// ...
}
int main() {
process<int>(42); // 显式指定 T 为 int
process<double>(3.14); // 显式指定 T 为 double
// 即使可以推导,也可以显式指定
process<string>("hello"); // 显式指定 T 为 string
return 0;
}
可以定义多个同名的函数模板:
// 处理单个参数
template <typename T>
void print(T value) {
cout << "单个值:" << value << endl;
}
// 处理两个参数
template <typename T1, typename T2>
void print(T1 a, T2 b) {
cout << "两个值:" << a << ", " << b << endl;
}
// 处理数组(特化形式)
template <typename T, int N>
void print(T (&arr)[N]) {
cout << "数组:";
for (int i = 0; i < N; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
当模板函数和普通函数重名时:
// 普通函数
void print(int value) {
cout << "普通函数:" << value << endl;
}
// 模板函数
template <typename T>
void print(T value) {
cout << "模板函数:" << value << endl;
}
int main() {
print(10); // 优先调用普通函数(精确匹配)
print(3.14); // 调用模板函数(生成 print<double>)
print('A'); // 调用模板函数(生成 print<char>)
print<>(10); // 强制调用模板函数(print<int>)
return 0;
}
为特定类型提供特殊实现:
// 通用模板
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
// 特化:针对 char* 类型
template <>
bool isEqual<char*>(char* a, char* b) {
return strcmp(a, b) == 0;
}
// 特化:针对 double 类型(处理浮点数精度问题)
template <>
bool isEqual<double>(double a, double b) {
return fabs(a - b) < 1e-6;
}
template <typename T>
auto getValue(T container) -> decltype(container.front()) {
return container.front();
}
// C++14 及以后可以更简洁
template <typename T>
auto getValue(T container) {
return container.front();
}
// C++20 引入的简写函数模板
auto print(auto value) {
// 等价于 template<typename T> void print(T value)
cout << value << endl;
}
auto max(auto a, auto b) {
// 可以处理不同类型参数
return (a > b) ? a : b;
}
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swapValues(x, y); // 交换整数
string s1 = "Hello", s2 = "World";
swapValues(s1, s2); // 交换字符串
return 0;
}
template <typename T, int N>
T findMax(T (&arr)[N]) {
T maxVal = arr[0];
for (int i = 1; i < N; i++) {
if (arr[i] > maxVal) {
maxVal = arr[i];
}
}
return maxVal;
}
int main() {
int intArr[] = {1, 5, 3, 9, 2};
cout << findMax(intArr) << endl; // 输出 9
double doubleArr[] = {1.1, 5.5, 3.3, 9.9, 2.2};
cout << findMax(doubleArr) << endl; // 输出 9.9
return 0;
}
template <typename T>
void bubbleSort(T arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swapValues(arr[j], arr[j + 1]);
}
}
}
}
由于模板是在编译时实例化的,通常需要将模板的完整定义放在头文件中。
// C++20 之前:缺乏类型约束
template <typename T>
T add(T a, T b) {
return a + b; // 如果 T 不支持 + 操作符,会在实例化时报错
}
// C++20:使用概念约束
template <typename T>
requires std::is_arithmetic_v<T> // 约束 T 必须是算术类型
T add(T a, T b) {
return a + b;
}
过多不同类型的实例化可能会导致代码体积增大。
模板的错误信息通常比较晦涩,因为错误在实例化时才被发现。
| 特性 | 函数模板 | 函数重载 |
|---|---|---|
| 目的 | 编写类型无关的通用代码 | 为不同类型提供不同实现 |
| 代码量 | 一份模板代码,多份实例 | 每个重载都需要单独实现 |
| 类型检查 | 实例化时检查 | 定义时检查 |
| 适用场景 | 算法相同,仅类型不同 | 不同类型需要不同处理逻辑 |
template <typename T> 声明模板参数函数模板极大地提高了代码的复用性,是 STL(标准模板库)的基石,使得编写类型安全且高效的通用算法成为可能。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online