1. 普通函数的调用:当我们调用一个普通函数时,编译器只需要掌握函数的声明。当使用类对象的成员函数时,编译器必须能够找到类类型的定义,但成员函数的定义不必已经出现,只需声明即可。所以我们可以将普通函数的声明和类定义放在头文件,把普通函数和类成员函数的定义放在源文件中。
2. 模板函数:为了能够生成一个实例化版本,编译器必须掌握函数模板或类模板成员函数的定义,因此与非模板代码不同,模板的头文件中通常既包含声明又包含定义。
编译:
因为模板直到实例化的时候才生成代码,所以大多数编译错误直到实例化期间才能得到。
第一阶段:编译模板本身。编译器会检查语法错误,比如忘记分号,或者变量名拼错。
第二阶段:编译器遇到模板被使用的时候。如:当只是作为一个函数声明的返回值时,因为此时还并没有实例化。所以,在此阶段,编译器也只会检查实参数目是否正确,以及是否匹配。如下图所示:此时是可以编译通过的,但是类A并没有定义。
template<typename T>
class A;
A<int> fun();
第三阶段:模板实例化。只有在这个阶段才可以发现类型相关的错误。依赖于编译器如何管理实例化,这类错误可能在链接时才报告。如下图所示,此时因为模板A已经实例化了,所以能够发现类A并没有定义,所以会报错“使用未定义的类型A<int>”。
template<typename T>
class A;
A<int> fun()
{
}
所以在函数的定义或者类定义中直接使用类模板的实例模板类而非引用,则在编译时就会对其实例化。
如下所示,编译也不会报错,因为此时编译器并未对模板类A实例化。
template<typename T>
A<T> fun1()
{
}
template<typename T>
void fun2(A<T>)
{
}类模板:
类模板是用来生成类的蓝图。与函数模板不同之处在于编译器不能为类模板推断出模板参数类型。默认情况下,一个类模板的成员函数只有当程序用到它的时候才会实例化。
显示实例化,因为当模板被使用的时候才会被实例化,所以当相同的实例可能出现在多个对象文件中。当两个或多个独立编译的源文件使用相同的模板,并提供了相同的模板参数时,每个文件中就会有该模板的实例。所以我们可以首先对某个实例显示实例化。
extern template declaration //实例化声明
template declaration //实例化定义extern说明在程序的其他位置有一个非extern的定义,对于一个给定的实例化版本,可以由多个extern声明,但定义只能有一个。
487

被折叠的 条评论
为什么被折叠?



