1.模板
我们要理解模板的分离编译,首先,了解什么是模板:
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
在c++中,我们大量使用的模板都是类模板。
2.模板的分离编译
在C++中,为了一个项目的规范化我们通常把代码归类为三类:声明文件、实现文件、测试文件。例如,用c++实现一个链表,它会有三个文件:List.h (链表相关声明)、List.cpp(链表相关实现)、test.cpp(链表测试文件)。
如果,我们用模板写链表,建立三个文件是否也是正确的呢?
我们可以简单看一个实例
//test.h 声明文件
template<class T>
class AA
{
public:
AA();
private:
int _a;
};
//test.cpp 实现文件
#include"test.h"
template<class T>
AA<T>::AA()
:_a(0)
{}
//main.cpp 测试文件
#include<iostream>
#include"test.h"
using namespace std;
int main()
{
AA<int> a1;
return 0;
}
但是,其实这是编译不过去的。因为,它会出现如下错误
这是因为编译AA<T>时没有实例化出AA<int>,所以链接时出错。
我们都知道模板需要两次编译,第一次编译是在实例化之前,用来检查基本的语法错误。第二次编译是在实例化之后,当把它实例化具体的类型时,再次判断有没有语法错误。
模板代码的实现在实现文件里,而实例化的测试代码在测试文件里,编译器编译时并不知道它们是分开的,也就是编译实现文件时并不知道实例化代码在测试文件里,就没有实例化出真正的代码,因此才会报出这样的错误。
3.解决办法
(1)在模板的实现文件里显示实例化;
(2)将定义和声明放在同一个文件里,命名为xxx.hpp;