将模板化方法定义移出头文件的优雅方法

时间:2013-11-03 22:15:59

标签: c++ templates

在我的一个C ++项目中,我使用了很多模板。由于我不能将它们放在* .cpp文件中,所以它们现在整个函数都存在于标题中。

但是一方面会弄乱头文件,另一方面会导致编译时间过长。如何以干净的方式处理模板化函数的实现?

3 个答案:

答案 0 :(得分:2)

您只需创建一个新的标题文件library_detail.hpp并将其包含在原始标题中。

我看到有些人也使用.t.template扩展来命名此实现标头文件。

答案 1 :(得分:2)

实际上并不要求模板必须在标题中。他们很可能在翻译单位。唯一的要求是编译器能够在使用它们时隐式地实例化它们,或者它们被明确地实例化。

是否将基于模板化的代码分离成标题和非标题是可行的,这在很大程度上取决于正在做什么。它工作得相当好,例如,对于IOStreams库,因为它实际上只是为字符类型charwchar_t实例化。编写显式实例化非常简单,即使有更多字符类型,例如char16_tchar32_t,它仍然可行。另一方面,以类似的方式分离std::vector<T>之类的模板是不可行的。

在子系统之间的接口中使用诸如std::vector<T>之类的通用模板很快就会成为一个主要问题:虽然具体的实例化或选定的实例化都可以,因为子系统可以在不作为模板的情况下实现,但使用任意实例化会强制执行整个系统都是模板。这样做在任何现实世界的应用程序中都是不可行的,这些应用程序通常在小端上有几百万行代码。

这相当于使用完全类型化的编译防火墙,并且不在子系统之间使用任意模板。为了简化子系统接口的使用,可以有薄模板包装器,例如,将一个容器类型转换成另一个容器,或者在可行的情况下对模板参数进行类型擦除。但是,需要认识到,编译分离通常以运行时性能成本出现:调用virtual函数比调用inline函数要昂贵得多。因此,子系统之间的抽象可能与子系统内的抽象非常不同。例如,迭代器是很好的内部抽象。在子系统之间,特定容器(例如某种类型std::vector<X>的{​​{1}})往往更有效。

请注意,模板的构建时交互是对特定实例的依赖所固有的。也就是说,即使有一个相当不同的声明和模板定义系统,例如,以模块系统的形式而不是使用头文件,将一切都变成模板也不可行。使用模板实现本地灵活性非常有效,但如果不在大型项目中全局修复实例化,它们就无法工作。

最后一个插件:here是关于如何组织实现模板的源的一篇文章。

答案 2 :(得分:1)

可以帮助的一件事是将不依赖于模板参数的功能分解为可以在实现文件中定义的非模板化辅助函数。

例如,如果您正在实现自己的向量类,则可以将大部分内存管理分解为非模板类​​,该类仅适用于非类型化的字节数组,并且在.cpp中具有其成员函数的定义文件。实际需要知道元素类型的函数在头文件中的模板化类中实现,并将大部分工作委托给非模板化的帮助者。

相关问题