将C++模板的实现放到CPP文件中

将C++模板的实现放到CPP文件中

1 年前 · 来自专栏 C++进阶和骚套路指南

阅读注意

定义 = 实现 = implement。 声明 = declare。

前文

写过一点C++的人应该都知道,一般而言,我们需要把模板的定义和实现 都放在头文件中 ,否则在链接的时候可能就会提示找不到外部符号。

也就是得这么写

// ClassicalTemplate.h
template<class T>
class MyTemplate
    T Member;
    void SetMember(const T& InMember);
    T GetMemebr();
template<T>
void MyTemplate<T>::SetMember(const T& InMember)
    Member = InMember;
template<T>
T MyTemplate<T>::GetMemebr()
    return Member;

然而这么写有个问题,就是有可能会降低编译的速度。

我们知道,如果一个头文件被include到了一百个CPP文件中,一旦这个头文件被修改了,那么这一百个CPP文件全都得重新编译。

由于函数体的内容会经常被修改,所以我们会尽量避免在头文件中实现函数,而是把它放到对应的CPP文件中来实现。这样子,不管CPP文件中的函数体如何修改,都只需要编译这个CPP文件本身。

补充头文件的相关知识: 知乎 rayhunter - 细说C++头文件

但是对于模板类或者模板函数来说,一般而言都是要求声明和定义全都要放在同一个头文件的,而不能分离到头文件和CPP文件中。

当然,这只是一般而言,本文就是探讨如何实现模板类的声明定义分析。

模板的隐式实例化

首先,来看看为什么模板的声明定义一般是放在同一个头文件的。详细的可以参考博客: 拾荒志 - C++模板声明和定义分离

文章大意是:

不管是类的实例化,还是模板的实例化,都是需要原型的信息的。对于类的实例化而言,原型信息是类本身,而对于模板的实例化,原型信息就是模板。


实例化模板的本质是在生成代码。也就意味着在实例化模板的时候,我们需要知道模板的全部信息,包括了类函数的定义。

普通情况下,模板在被使用的时候才会被「实例化」成对应的代码。这个实例化的过程是「隐式」的,当编译器意识到你在使用这个模板,就会自动帮你实例化。

#include "MyTemplate.h"
int main()
    MyTemplate<int> MyIntTemplate;

上面这段代码会使得生成的时候,实例化一个int版本的模板。

由于所有的模板信息都定义在头文件 "MyTemplate.h" 中,所以能够成功地实例化,没有问题。

模板的显式实例化

既然生成的时候会自动识别模板的使用和自动实例化模板,那有没有方法主动实例化模板呢?有,这个就叫做模板的显式实例化。

接下来我们把前面头文件中的函数实现移动到对应的CPP文件中。

#include "MyTemplate.h"
template<class T>
T MyTemplate<T>::GetMember()
    return this->Member;
template<class T>