我曾经(并且已经很长时间)认为你必须完全定义.h文件中的所有模板函数,以避免因模板编译过程而发生的多个定义错误(非C ++ 11) )。
我正在读一个同事的代码,他有一个非模板类,其中有一个模板函数,并且他将函数声明与函数定义(在H中声明,在CPP中定义)分开。它令我惊讶地编译并正常工作。
非模板类中的模板函数如何编译,以及如何编译模板类中的函数之间是否存在差异?有人可以解释这种差异或者我可能会感到困惑的地方吗?
答案 0 :(得分:4)
有趣的是模板实例化的方式和时间。如果可以在链接时找到实例化,则不需要在头文件中显示模板 definition 。
有时,显式实例化是这样的原因:
标题:
struct X {
// function template _declaration_
template <typename T> void test(const T&);
};
CPP:
#include "X.h"
// function template _definition_:
template <typename T>
void X::test(const T&)
{
}
// explicit function template _instantiation(s)_:
template X::test<int>(const int&);
template X::test<std::string>(const std::string&);
使用此示例,除非在其他翻译单元中使用模板的未实例化定义,否则链接将成功
答案 1 :(得分:3)
在命名空间或类范围中定义的函数模板之间没有区别。是否在类模板内也无关紧要。重要的是,在项目的某个时刻,任何使用过的函数模板(无论是成员还是非成员)都会被实例化。让我们回顾一下不同的情况:
这些大致是重要的选择。通常有很好的理由不希望在标题中定义函数模板。例如,您不一定要拖动您不会拥有的依赖项。将函数模板的定义放在其他地方并明确地实例化它是一件好事。此外,您可能希望减少编译时间,例如通过避免使用流在每个转换单元中实质上实例化整个I / O流和语言环境库。在C ++ 2011中引入了 extern templates ,它允许声明特定模板(函数或类模板)在外部为整个程序定义一次,并且不需要在每个头中实例化它使用特别常见的模板参数。
对于我刚才所说的更长版本,包括示例,请查看blog post 我上周末写了这个话题。