在其他语言中,你可能听说过它的别名——泛型,但是模板要比泛型的作用更加强大
模板比较像宏,可以自由定义,而泛型会受制于类型系统和其他因素
模板允许用户根据自身用途定义一个可编译的“模板”,就是给编译器一套规则,让它帮你自动填充代码
例如,写一个模板函数时,就是创建一个函数规则,当用户调用这个函数时,通过指定特定的参数,决定函数中应该填充的实际代码,从而决定函数的实际使用情况
#include<iostream>
void Print(int value)
{
std::cout << value << std::endl;
}
void Print(float value)
{
std::cout << value << std::endl;
}
void Print(std::string value)
{
std::cout << value << std::endl;
}
int main() {
Print(5);
Print("Hello");
Print(3.5f);
}同一个函数因为传入参数类型的参数需要重载,当修改函数逻辑时需要对每个函数进行操作,过于繁琐
#include<iostream>
template<typename T>
void Print(T value)
{
std::cout << value << std::endl;
}
int main(){
Print(5);
Print("Hello");
Print(3.5f);
}使用 template 定义模板函数,模板函数并不是一个真正的函数,只在调用的时候才会创建。调用函数时根据传入的参数确定函数的实际代码
使用 typename 作为模板参数类型,T 作为名字
函数调用看着像是显式指定参数类型,实际上是隐式地从实际参数中获取
#include<iostream>
template<typename T>
void Print(T value)
{
std::cout << value << std::endl;
}
int main(){
//传入int类型参数是非法的
Print<std::string>(5);
}模板函数会自动获取传入参数类型,并在<>中填写参数类型
模板函数是在调用时创建,如果没有调用模板函数,则模板函数的代码如同不存在
#include<iostream>
template<typename T>
void Print(T value)
{
std::cout << valu << std::endl;
}
int main(){
}使用不存在的变量名不会出现错误(不同的编译器可能存在差异),如果调用 Print 函数则会出现变量未定义错误
#include<iostream>
template<typename T, int N>
class Array {
private:
T m_Array[N];
public:
int getSize() const {
return N;
}
};
int main(){
Array<std::string, 50> array;
std::cout << array.getSize() << std::endl;
}STL 中大多使用了模板,可以通过用户传入参数自动创建对应的类
TIP
不要过度使用模板,期望编译器自动生成复杂工程代码将会是一场灾难,因为梳理代码逻辑时无法清晰地知晓代码内容,甚至需要动手记录生成的类型信息。此外,可能存在未使用的模板代码干扰你的排查思路