简单易懂的比喻+代码示例+逐步递进,让你学得轻松又扎实!
假设你写了一个 计算两个数之和 的函数:
int add(int a, int b) {
return a + b;
}
✅ 可以处理整数 int
,但如果想计算 小数 double
呢?
你得再写一个函数:
double add(double a, double b) {
return a + b;
}
⚠️ 问题: 代码重复!不同类型的数据都要单独实现,怎么办?
模板 来解决!
template
T add(T a, T b) {
return a + b;
}
template
:告诉编译器 T 是一个占位符,代表"某种类型"。T add(T a, T b)
:参数 a
、b
和返回值的类型都是 T
,编译时会替换成具体类型。#include
// 定义函数模板
template
T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(3, 5) << std::endl; // T = int
std::cout << add(3.14, 2.71) << std::endl; // T = double
}
编译器会自动推导 T
的类型:
add(3, 5)
→ int add(int a, int b)
add(3.14, 2.71)
→ double add(double a, double b)
问题: 你写了一个 存储整数 的
Box
类:
class Box {
private:
int value;
public:
Box(int v) : value(v) {}
int getValue() { return value; }
};
但如果想存 double
或 std::string
呢?
✅ 类模板 让 一个类 适用于 所有类型!
template
class Box {
private:
T value;
public:
Box(T v) : value(v) {}
T getValue() { return value; }
};
#include
// 定义类模板
template
class Box {
private:
T value;
public:
Box(T v) : value(v) {}
T getValue() { return value; }
};
int main() {
Box intBox(10); // T = int
Box doubleBox(3.14); // T = double
Box strBox("Hi"); // T = std::string
std::cout << intBox.getValue() << std::endl;
std::cout << doubleBox.getValue() << std::endl;
std::cout << strBox.getValue() << std::endl;
}
T 被替换成不同类型,一个模板搞定所有情况!
模板不仅可以接受类型参数,还可以接受常量参数!
template
class Array {
private:
T data[N]; // N 是数组大小
public:
int size() { return N; }
};
#include
// 定义类模板,N 是数组大小
template
class Array {
private:
T data[N];
public:
int size() { return N; }
};
int main() {
Array arr1; // T = int, N = 5
Array arr2; // T = double, N = 10
std::cout << arr1.size() << std::endl; // 输出 5
std::cout << arr2.size() << std::endl; // 输出 10
}
N
是常量,必须在编译时确定,不能传变量!
问题: 如果
Box
需要特殊处理,怎么办?
✅ 模板特化(Template Specialization) 允许我们针对特定类型提供不同实现!
#include
// 普通模板
template
class Box {
public:
void print(T value) {
std::cout << "普通值: " << value << std::endl;
}
};
// 针对 std::string 特化
template <>
class Box {
public:
void print(std::string value) {
std::cout << "字符串: " << value << std::endl;
}
};
int main() {
Box intBox;
intBox.print(42); // 输出:普通值: 42
Box strBox;
strBox.print("Hello"); // 输出:字符串: Hello
}
特化后的 Box
代码与普通模板不同,实现了不同逻辑!
问题: 有时候,函数/类的参数个数不固定,怎么办?
✅ 可变参数模板(Variadic Template) 允许任意数量的模板参数!
#include
// 递归终止条件
void print() { std::cout << std::endl; }
// 递归展开参数
template
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...); // 递归展开剩余参数
}
int main() {
print(1, "Hello", 3.14, "C++", 42);
}
编译器会递归展开参数,直到 print()
没有参数,终止递归。
特性 | 作用 |
---|---|
函数模板 | 适用于 任意类型 的函数 |
类模板 | 适用于 任意类型 的类 |
非类型模板参数 | 模板参数不仅限于类型,还可以是整数常量 |
模板特化 | 针对特定类型 提供不同实现 |
可变参数模板 | 允许 任意数量的模板参数 |