C++模板是泛型编程的基础工具,允许开发者编写与数据类型无关的代码,通过参数化类型让同一套逻辑可以适配不同的数据类型,大幅减少重复代码的编写量。模板主要分为函数模板和类模板两类,分别对应函数和类的泛型化实现。

函数模板的定义与使用
函数模板用于定义可以处理多种数据类型的通用函数,定义时需要先声明模板参数,再定义函数逻辑。模板参数通常用typename或者class关键字声明,两者在模板参数声明时没有区别。
函数模板基本定义语法
函数模板的定义格式如下:
// 声明模板参数T,T代表一个待定的数据类型
template <typename T>
// 函数返回值、参数都可以使用模板参数T
T add(T a, T b) {
return a + b;
}
函数模板的调用方式
函数模板调用时可以通过显式指定模板参数类型,也可以让编译器自动推导类型:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
// 编译器自动推导T为int类型
int intResult = add(1, 2);
cout << "int result: " << intResult << endl;
// 显式指定T为double类型
double doubleResult = add<double>(1.5, 2.3);
cout << "double result: " << doubleResult << endl;
return 0;
}
函数模板的匹配规则
当存在普通函数和同名的函数模板时,编译器会优先匹配普通函数,只有当普通函数不匹配时才会选择函数模板。如果希望强制使用函数模板,可以在调用时显式指定空的模板参数列表:
#include <iostream>
using namespace std;
// 普通函数
int add(int a, int b) {
cout << "调用普通函数" << endl;
return a + b;
}
// 函数模板
template <typename T>
T add(T a, T b) {
cout << "调用函数模板" << endl;
return a + b;
}
int main() {
add(1, 2); // 匹配普通函数
add<>(1, 2); // 强制匹配函数模板,T推导为int
add(1.5, 2.3); // 没有匹配的普通函数,匹配函数模板,T推导为double
return 0;
}
类模板的定义与使用
类模板用于定义可以适配多种数据类型的通用类,比如标准库中的vector、map等都是类模板的实现。类模板的定义和函数模板类似,需要先声明模板参数,再定义类的成员。
类模板基本定义语法
类模板的定义格式如下,模板参数可以有一个或多个:
// 声明两个模板参数T1和T2
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
类模板的实例化
类模板不能直接使用,必须先指定模板参数类型进行实例化,生成具体的类之后才能创建对象:
#include <iostream>
using namespace std;
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
int main() {
// 实例化Pair类,T1为int,T2为string
Pair<int, string> p1(1, "one");
cout << p1.getFirst() << " " << p1.getSecond() << endl;
// 实例化Pair类,T1为double,T2为double
Pair<double, double> p2(3.14, 2.71);
cout << p2.getFirst() << " " << p2.getSecond() << endl;
return 0;
}
类模板成员函数的外部实现
如果类模板的成员函数需要在类外部定义,需要加上模板参数声明,并且类作用域要带上模板参数:
#include <iostream>
using namespace std;
template <typename T>
class MyArray {
private:
T* data;
int size;
public:
MyArray(int s);
~MyArray();
T getData(int index) const;
};
// 构造函数外部实现
template <typename T>
MyArray<T>::MyArray(int s) : size(s) {
data = new T[size];
}
// 析构函数外部实现
template <typename T>
MyArray<T>::~MyArray() {
delete[] data;
}
// 普通成员函数外部实现
template <typename T>
T MyArray<T>::getData(int index) const {
if (index >= 0 && index < size) {
return data[index];
}
return T();
}
int main() {
MyArray<int> arr(5);
return 0;
}
模板编程的注意事项
- 模板的代码通常写在头文件中,因为模板的实例化是在编译阶段完成的,编译器需要看到完整的模板定义才能生成对应类型的代码。
- 模板参数可以有默认值,比如
template <typename T = int>,实例化时如果不指定T的类型,就会使用默认的int类型。 - 可以为模板定义特化版本,当模板参数匹配特定类型时,使用特化的实现逻辑,比如针对bool类型优化存储结构。
- 模板不支持分离编译,不要将模板的声明放在头文件,定义放在源文件,否则会导致链接错误。