模板(Template)概述
模板是 C++ 中的一种泛型编程机制,允许编写通用的代码,可以在不指定具体数据类型的情况下定义函数、类或结构体。模板的主要目的是提供代码的复用性和灵活性,从而支持处理多种数据类型的能力。
C++ 中的模板主要分为两种:
- 函数模板(Function Template)
- 类模板(Class Template)
1. 函数模板
函数模板是定义一个可以操作多种数据类型的函数。通过模板,函数可以在调用时根据传递的参数类型自动生成具体的函数。
1.1 函数模板的基本语法
1 2 3 4 5 6 7 8 9 10
| template <typename T> T add(T a, T b) { return a + b; }
int main() { cout << add<int>(3, 4) << endl; cout << add(3.5, 4.2) << endl; return 0; }
|
输出:
1.2 关键点
template <typename T>
:定义模板,其中 T
是占位符,表示数据类型。
- 也可以使用
class
代替 typename
(两者在模板声明中等价)。
- 模板函数的具体类型可以显式指定(如
add<int>(3, 4)
),也可以通过参数隐式推导(如 add(3.5, 4.2)
)。
1.3 函数模板的特例化
有时我们希望对某些特定类型提供专门的实现,可以通过模板特例化实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> using namespace std;
template <typename T> T max(T a, T b) { return (a > b) ? a : b; }
template <> const char* max<const char*>(const char* a, const char* b) { return (strcmp(a, b) > 0) ? a : b; }
int main() { cout << max(3, 7) << endl; cout << max("apple", "banana") << endl; return 0; }
|
说明:
- 特例化版本定义了针对
const char*
类型的专门实现。
- 当模板匹配到
const char*
类型时,会优先使用特例化版本。
2. 类模板
类模板是为实现通用的类而设计的,允许类操作不同类型的数据而不需要重复编写代码。
2.1 类模板的基本语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream> using namespace std;
template <typename T> class MyClass { private: T data; public: MyClass(T value) : data(value) {}
void display() { cout << "Value: " << data << endl; } };
int main() { MyClass<int> obj1(10); MyClass<double> obj2(3.14);
obj1.display(); obj2.display();
return 0; }
|
说明:
template <typename T>
定义了一个类模板。
- 模板类实例化时,需要为模板参数
T
提供具体类型,如 MyClass<int>
。
2.2 类模板的特例化
和函数模板一样,类模板也可以为某些特定类型提供特例化实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream> using namespace std;
template <typename T> class MyClass { public: void display() { cout << "Generic template" << endl; } };
template <> class MyClass<int> { public: void display() { cout << "Specialized template for int" << endl; } };
int main() { MyClass<double> obj1; MyClass<int> obj2;
obj1.display(); obj2.display();
return 0; }
|
说明:
- 通用模板适用于所有类型,但当实例化类型为
int
时,会使用特例化版本。
2.3 类模板的部分特例化
类模板还支持部分特例化,即只对部分模板参数进行特例化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream> using namespace std;
template <typename T, typename U> class MyClass { public: void display() { cout << "Generic template" << endl; } };
template <typename T> class MyClass<T, int> { public: void display() { cout << "Partial specialization for second type int" << endl; } };
int main() { MyClass<double, double> obj1; MyClass<double, int> obj2;
obj1.display(); obj2.display();
return 0; }
|
说明:
- 部分特例化可以只针对某些类型参数组合,提供更灵活的设计。
3. 模板的其他用法
3.1 模板默认参数
模板参数可以提供默认值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> using namespace std;
template <typename T = int> class MyClass { public: void display() { cout << "Type: " << typeid(T).name() << endl; } };
int main() { MyClass<> obj; MyClass<double> obj2;
obj.display(); obj2.display();
return 0; }
|
3.2 模板模板参数
模板参数本身可以是模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <vector> using namespace std;
template <template <typename, typename> class Container> class MyClass { public: void display() { Container<int, allocator<int>> c = {1, 2, 3}; for (int x : c) { cout << x << " "; } cout << endl; } };
int main() { MyClass<vector> obj; obj.display(); return 0; }
|
说明:
template <template <typename, typename> class Container>
定义了模板模板参数。
- 实例化时,
vector
作为模板模板参数被传递。
4. 编译期计算与模板
模板可以用于编译期计算,例如实现递归的斐波那契数列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> using namespace std;
template <int N> struct Fibonacci { static const int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value; };
template <> struct Fibonacci<0> { static const int value = 0; };
template <> struct Fibonacci<1> { static const int value = 1; };
int main() { cout << Fibonacci<10>::value << endl; return 0; }
|
说明:
- 模板通过递归定义实现了编译期的斐波那契数列计算。
Fibonacci<10>
会在编译时计算出结果。
总结
模板是 C++ 强大的泛型编程工具,其主要特点包括:
- 函数模板 和 类模板。
- 支持特例化(全特例化和部分特例化)。
- 提供了编译期计算能力。
- 与 STL 紧密结合,广泛用于算法和容器中。
模板大大提高了代码的复用性和通用性,但模板的编译错误通常比较复杂,因此需要小心使用。