C++ Template 基础篇(一):函数模板
(2025–2026 年最实用、最清晰的入门讲解)
函数模板是 C++ 模板机制的入门级也是最常用的部分。
掌握函数模板后,你就能写出类型无关、复用性极高的代码,这是现代 C++(尤其是泛型编程)的基石。
1. 什么是函数模板?
一句话定义:
函数模板 = “写一次函数,让编译器根据调用时的参数类型自动生成多个具体版本的函数”
换句话说:你只写一份代码,编译器帮你生成 int 版、double 版、string 版、自定义类版…… 所有需要的版本。
2. 最经典的例子:求最大值
传统写法(重复劳动)
int max(int a, int b) { return a > b ? a : b; }
double max(double a, double b) { return a > b ? a : b; }
long long max(long long a, long long b) { return a > b ? a : b; }
// …… 每种类型都要写一遍,太痛苦
用函数模板(一次编写,到处使用)
template <typename T> // 或 template <class T>(两者等价)
T max(T a, T b) {
return a > b ? a : b;
}
使用方式:
int main() {
cout << max(3, 7) << endl; // 调用 int 版本
cout << max(2.5, 1.8) << endl; // 调用 double 版本
cout << max(100LL, 200LL) << endl; // 调用 long long 版本
string s1 = "apple", s2 = "banana";
cout << max(s1, s2) << endl; // 调用 string 版本(按字典序比较)
}
编译器在编译时会自动为每种调用生成一份具体函数(称为模板实例化)。
3. 模板语法核心关键词
| 写法 | 含义 | 现代推荐写法(C++11+) |
|---|---|---|
template <typename T> | T 是类型参数 | 推荐(最清晰) |
template <class T> | 与上面完全等价 | 历史写法,仍合法 |
template <typename T1, typename T2> | 多个类型参数 | 常见于 map、pair 等 |
template <int N> | 非类型参数(常量) | 后面会讲 |
4. 函数模板的推导规则(最容易出错的地方)
编译器如何决定 T 是什么?
规则总结(优先级从高到低):
- 显式指定类型(最强,强制使用)
max<double>(3, 4.5); // 强制 T = double,3 会被隐式转换为 double
- 根据实参自动推导(最常见)
max(10, 20); → T = int
max(1.2f, 3.4); → T = float
- 常见陷阱:不同类型实参时推导失败
max(10, 3.14); // 错误!编译器不知道 T 应该是 int 还是 double
解决办法(三种任选):
// 方案1:显式指定
max<double>(10, 3.14);
// 方案2:统一类型
max(10.0, 3.14);
// 方案3:重载或使用模板重载(后面会讲)
5. 模板函数的重载与特化
模板函数也可以和普通函数、其他模板函数一起重载。
// 普通函数(优先级最高)
int max(int a, int b) {
cout << "调用普通函数\n";
return a > b ? a : b;
}
// 模板函数
template <typename T>
T max(T a, T b) {
cout << "调用模板\n";
return a > b ? a : b;
}
// 调用
max(5, 3); // → 调用普通函数(非模板函数优先)
max(5.0, 3.0); // → 调用模板(没有匹配的普通函数)
模板特化(针对特定类型写特殊版本)
// 针对 const char* 的特化版本(字符串比较用 strcmp)
template <>
const char* max<const char*>(const char* a, const char* b) {
return strcmp(a, b) > 0 ? a : b;
}
6. 非类型模板参数(C++11 前就存在,很实用)
template <int N>
void print_fixed_size_array(int (&arr)[N]) {
for (int i = 0; i < N; ++i) {
cout << arr[i] << " ";
}
}
int main() {
int a[5] = {1,2,3,4,5};
print_fixed_size_array(a); // N 自动推导为 5
}
7. 2026 年写函数模板的现代最佳实践
// 推荐写法(C++20 概念 + auto 参数)
#include <concepts>
// 要求 T 支持 < 运算符
template <typename T>
requires std::totally_ordered<T> // C++20 概念约束
T my_max(T a, T b) {
return a < b ? b : a;
}
// 更现代:C++20 缩写语法
auto my_max(std::totally_ordered auto a, std::totally_ordered auto b) {
return a < b ? b : a;
}
8. 小结:函数模板一句话记住
函数模板让你写一份代码,编译器自动生成 N 份类型特化的函数。
核心口诀:
- 用
template <typename T>开头 - T 代表“任意类型”
- 编译器在调用时自动推导或显式指定 T
- 重复参数类型自动去重,优先匹配普通函数
- 想限制类型 → 用 C++20 概念(requires)
下一篇文章可以继续讲:
- 类模板(class template)
- 模板特化 & 偏特化
- 变参模板(variadic template)
- C++20 概念(concepts)实战
你想现在就继续看“类模板”还是先做几个函数模板练习题?或者有具体的使用场景(排序、比较、打印容器等)想看示例?告诉我,我立刻写给你。