模板初阶
泛型编程: 编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
初阶模板:
- 函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型生成函数的特定版本。
语法: template<typename/class 参数T1, typename/class 参数T2, …>
返回值类型 函数名( 参数 形参 ,…) // T1和T2当作类型用就可以了,返回值类{ 型也可以是参数
…
}
函数模板的实例化:根据函数模板和调用类型 编译器自动生成的函数 称为模板的实例化
参数的类型是根据传入的实参的类型进行推演得到的
Eg:
看似调用的是void Swap(T& left , T& right);
其底层实际上调用的是编译器用模板生成的函数(这称为模板的实例化)。
实际上C++库中有swap函数,其实现也是通过模板。
当left和right的类型不同时, 那么返回的时候,T就不清楚返回那种类型因此报错。
解决方法:
- 传参时对参数进行强转
- 显式实例化: 不再推演参数
函数名< 类型 > (函数调用传入的参数)
模板参数 就是 此处<类型>中的 类型
- 模板设置两个参数,并且Auto 做模板函数的返回值
当函数的形参固定了,那么T就无法推演了,因此这种情况的解决方法也是 对函数模板进行实例化。 即通过: func<int>(m); 类型的调用
当有最匹配的函数,那么就调用最匹配的函数。
如果没有最匹配的函数,那么就调用能生成最匹配的函数的模板函数
Eg:
Add( a , b);
a , b 如果都是int类型, 那么调用的是 int Add(int left , int right);
a , b 如果是并不是都是 int 类型 , 那么调用的是 此处的模板函数, 即通用加法函数
二. 类模板:
类模板使用必须实例化
语法:
Template < typename/class 参数T1 , … >
Class 自定义类名
{
…
}
Eg:
参数是通过实例化指定的。
st1存储int数据的 Stack类 ,st2 存储 double 类数据的 Stack类。
st1的类型是 Stack<int> , st2的类型是Stack<double> 。即st1和st2是两种不同的类型
类模板的成员函数的声明和定义分离:
语法:
Template <typename/class 参数1 , typename/class 参数2 ,…>
返回值类型 类名<参数1,…> : : 函数名(形参)
{
…
}
注意: 类模板的成员函数的声明和定义分离只能在本文件中进行,不能声明在.h文件,定义在.cpp文件,会导致链接错误。 因此不建议类模板的成员函数的声明和定义分离到了两个文件