类模板和函数模板都是模板,并不是真正的函数和类,只有给了模板参数才能实例化出函数和类
a.类模板有两种给模板参数的方式1.显式给2.缺省给
b.函数模板有三种给模板参数方式:1.显式给 2.缺省给 3.推导给
调用函数时,参数列表中如果有模板参数,则编译器可以通过函数参数推导模板参数
1. 类模板(Class Template)
类模板用于定义 与类型无关的类,使用时需要显式或隐式指定模板参数来实例化具体的类。
(1) 定义类模板
cpp
template <typename T> // T 是模板参数 class MyVector { private: T* data; size_t size; public: MyVector(size_t n) : data(new T[n]), size(n) {} ~MyVector() { delete[] data; } T& operator[](size_t i) { return data[i]; } };
(2) 实例化类模板
类模板 必须显式或隐式(缺省)提供模板参数,编译器才能生成具体的类:
cpp
// 方式1:显式指定模板参数 MyVector<int> vec1(10); // 实例化 MyVector<int> // 方式2:使用缺省模板参数(如果类模板定义了缺省值) template <typename T = double> // 缺省类型为 double class MyContainer { /*...*/ }; MyContainer<> vec2; // 实例化 MyContainer<double>
2. 函数模板(Function Template)
函数模板用于定义 与类型无关的函数,模板参数可以通过 显式指定、缺省值或编译器推导 确定。
(1) 定义函数模板
cpp
template <typename T> // T 是模板参数 T max(T a, T b) { return (a > b) ? a : b; }
(2) 调用函数模板
函数模板的模板参数可以通过 三种方式 确定:
方式1:显式指定
cpp
int a = 3, b = 5; cout << max<int>(a, b); // 显式指定 T = int
方式2:缺省模板参数(C++11 起支持)
cpp
template <typename T = int> // 缺省类型为 int T getDefault() { return T{}; } auto x = getDefault<>(); // 使用缺省值 T = int
方式3:编译器自动推导
如果函数参数中使用了模板参数,编译器可以通过 实参类型 推导模板参数:
cpp
double c = 2.5, d = 3.7; cout << max(c, d); // 编译器推导 T = double
推导规则:
-
如果所有实参类型一致,
T
被推导为该类型。 -
如果实参类型不一致(如
max(3, 4.5)
),可能推导失败(除非使用std::common_type
或 C++17 的auto
参数)。
3. 关键区别:类模板 vs 函数模板
特性 | 类模板 | 函数模板 |
---|---|---|
实例化方式 | 必须显式或隐式提供模板参数 | 可显式指定、缺省或编译器推导 |
缺省参数支持 | 支持(C++11) | 支持(C++11) |
类型推导 | 不支持(必须指定类型) | 支持(可通过参数推导) |
4. 进阶技巧
(1) 模板参数自动推导(C++17)
C++17 引入了 类模板参数推导(CTAD),允许编译器根据构造函数参数推导类模板参数:
cpp
std::pair p(1, 3.14); // 推导为 std::pair<int, double> std::vector v = {1, 2, 3}; // 推导为 std::vector<int>
(2) 非类型模板参数
模板参数可以是 类型(typename T
) 或 值(如 int N
):
cpp
template <typename T, int N> class Array { T data[N]; public: T& operator[](int i) { return data[i]; } }; Array<int, 10> arr; // N = 10
(3) 可变参数模板(Variadic Templates)
支持任意数量和类型的模板参数:
cpp
template <typename... Args> void print(Args... args) { (std::cout << ... << args) << "\n"; // C++17 折叠表达式 } print(1, "hello", 3.14); // Args 被推导为 int, const char*, double
5. 总结
-
泛型编程 通过 模板 实现代码复用,编写与类型无关的代码。
-
类模板:
-
必须显式或隐式(缺省)提供模板参数。
-
不支持类型推导(C++17 前)。
-
-
函数模板:
-
支持 显式指定、缺省值、编译器推导 三种方式。
-
类型推导依赖于函数参数。
-
-
现代 C++ 扩展了模板能力(如 CTAD、可变参数模板等)。