模版template
模板
模板可用应用于函数,也可应用于类。
应用于函数的为函数模板,应用于类的为类模板。
模板参数–很多地方和函数参数类似
函数参数:传递的是对象值
模板参数:传递的是类型
函数模板的类型一般是编译器根据实参传递给形参的类型推演出来的,但是也有推演不出来的时候:
例1:
1 | template < class T > |
推到不出来模板参数T的类型,因为模板参数应用在了返回值类型上
没有办法通过传参判断出来模板参数的类型
此时应显式指定模板参数类型,“函数模板显式实例化”:
1 | int main() |
例2:
1 | template <class T> |
模板参数也可以缺省(用的比较少):
1 | template <class T = char> //缺省值为char |
模版的声明、定义可以分离
但是每个定义、声明前都要重新规定一下模版参数(的名称)
1 | template <class T> |
《但是模版不支持声明和定义分离到两个文件!!》
会报编译错误
此种情况都是对于分离式编译来说的
通常来讲,分离式编译有三类文件,包含程序入口main函数的文件(暂且称之为main文件)、包含自定义对象和函数声明的自定义头文件(暂且称之为头文件)、实现头文件中的对象和函数的cpp文件(暂且称之为实现文件)
一般是main文件和实现文件都包含头文件,然后通过实现文件实现头文件。最后链接到一起。
当然,main文件不要包含实现文件,否则不叫分离编译了
若实现文件被包含在了main文件中,展开后还是都在了main文件,最后结果还是声明、实现都在同一个文件也就是main文件中,并没有分离开来
此处指的声明和定义分离,就是指声明在头文件中,实现/定义在实现文件中。
为什么模版的声明和定义分离到2个文件中就会报编译错误?
符号表找不到(编译原理会提到)
程序编译的过程:
而模版参数只有在实例化的时候,才能借由实参传递形参推演出来参数类型,故在链接之前,负责模版实现的.cpp文件无法单独推演出模版参数(因为模版实例化是在main.cpp中进行的,此时都处在链接之前,都是分别独立处理的),因此负责实现的.cpp文件无法编译通过
解决方式
方案一(比较挫):在用于实现模版的.cpp中针对main中要使用的模版类型显式实例化
比如已知main.cpp中调用了函数模版,并且实例化参数为char
1 | //main.cpp |
那么就在实现的.cpp中显式实例化一个出一个char类型的模版
1 | //test.cpp |
方案二:声明和定义不分离,将模版的实现写在声明的头文件里,文件后缀命名为.hpp(建议)
后缀名建议更改,并不是强制更改,文件名后缀本质上对于文件没有任何影响,.cpp .h .hpp没有本质上的区别
.hpp 只是寓意更好,是.h和.cpp拼接成的,也就是“既有定义又有实现”的意思
调用顺序
在调用函数/实例化对象的时候,如果有已定义好的、(参数类型)更精确的,先调用已定义好的
没有,才调用模版,进行推演
若就是想强制指定调用模版,则调用时使用显式实例化
1 | Add<int>(a,b); |