为什么模板只能在头文件中实现?

新手上路,请多包涵

引用 C++ 标准库:教程和手册

目前使用模板的唯一可移植方式是通过使用内联函数在头文件中实现它们。

为什么是这样?

(澄清:头文件不是 唯一 的可移植解决方案。但它们是最方便的可移植解决方案。)

原文由 MainID 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 774
2 个回答

警告: 没有 必要将实现放在头文件中,请参阅此答案末尾的替代解决方案。

无论如何,您的代码失败的原因是,在实例化模板时,编译器会使用给定的模板参数创建一个新类。例如:

 template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f;

阅读此行时,编译器会创建一个新类(我们称之为 FooInt ),相当于如下:

 struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

因此,编译器需要访问方法的实现,以使用模板参数实例化它们(在本例中为 int )。如果这些实现不在标头中,它们将无法访问,因此编译器将无法实例化模板。

一个常见的解决方案是在头文件中编写模板声明,然后在实现文件(例如 .tpp)中实现类,并在头文件的末尾包含这个实现文件。

Foo.h

 template <typename T>
struct Foo
{
    void doSomething(T param);
};

#include "Foo.tpp"

文件.tpp

 template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}

这样,实现仍然与声明分离,但编译器可以访问。

替代解决方案

另一种解决方案是保持实现分离,并显式实例化您需要的所有模板实例:

Foo.h

 // no implementation
template <typename T> struct Foo { ... };

Foo.cpp

 // implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

如果我的解释不够清楚,您可以查看 有关此主题的 C++ Super-FAQ

原文由 Luc Touraille 发布,翻译遵循 CC BY-SA 4.0 许可协议

我建议查看这个 gcc 页面,该页面讨论了模板实例化的“cfront”和“borland”模型之间的权衡。

https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Template-Instantiation.html

“borland”模型对应于作者的建议,提供完整的模板定义,并多次编译。

它包含有关使用手动和自动模板实例化的明确建议。例如,“-repo”选项可用于收集需要实例化的模板。或者另一种选择是使用“-fno-implicit-templates”禁用自动模板实例化以强制手动模板实例化。

根据我的经验,我依赖于为每个编译单元实例化的 C++ 标准库和 Boost 模板(使用模板库)。对于我的大型模板类,我会为我需要的类型进行一次手动模板实例化。

这是我的方法,因为我提供的是工作程序,而不是用于其他程序的模板库。这本书的作者 Josuttis 在模板库方面做了很多工作。

如果我真的担心速度,我想我会探索使用预编译头 https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html

这在许多编译器中获得了支持。但是,我认为模板头文件很难预编译头文件。

原文由 Juan 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题