【问题标题】:Template instantiaton in multiple files多个文件中的模板实例化
【发布时间】:2014-02-17 01:59:52
【问题描述】:

我目前正在实现与通用字符串相关的模板类,它可以做很多复杂的事情。为了优化编译时间,我考虑在翻译单元而不是头文件中实现功能,然后为 UTF-8、UTF-16 和 UTF-32 实例化类型。我试图弄清楚的瓶颈是,如果可以将模板类实例化为多个翻译单元,因为一组成员函数所做的是非常复杂的代码,将其分离成很有意义它是自己的翻译单元。

这是我正在尝试做的示例:

example.h

template <typename T>
class Example
{
public:
  void test1();
  void test2();
};


example_test1.cpp

template <typename T>
void Example::test1()
{
  ...
}

template class Example<uint8_t>;
template class Example<uint16_t>;
template class Example<uint32_t>;


example_test2.cpp

template <typename T>
void Example::test2()
{
  ...
}

template class Example<uint8_t>;
template class Example<uint16_t>;
template class Example<uint32_t>;


明显(和 hacky)的解决方案是创建包含 example_test1.cpp 和 example_test2.cpp 的迷你“统一构建”,但这样做有点便宜,而且只有一个翻译单元。不知道有没有更好的解决方案?

编辑:如果您的答案是“将其放在标题中”,请不要这样做。那没有帮助。这里的想法是通过从头文件中删除不需要的内容来优化编译时间。由于头文件中过度使用模板,我们的编译时间已经很长了。而且我不需要关于如何使用其他方式优化编译时间的提示。我知道如何使用预编译的标头等。如果我能得到与主题相关的答案。

【问题讨论】:

  • 将成员函数定义拆分成单独的文件究竟有什么好处?而且您使用的术语也没有意义。您谈到将它们保存在单独的翻译单元中,但随后提到了一种可能的解决方案,即有一些预构建过程将它们全部包含在一个文件中。好了,现在您已经创建了一个翻译单元!我建议您停止思考,只需将所有定义放入同一个文件中即可。如果您的模板仅对这 3 种类型有用,则可以采用显式实例化路线。最后,考虑将char16_tchar32_t 用于UTF-16/32
  • Praetorian:我并没有想太多。该代码非常复杂,将其拆分为两个翻译单元使其更具可读性。我建议的解决方案很老套,是的,最终会得到一个翻译单元。这就是为什么我正在寻找更好的解决方案。而且我无法使用任何 C++11 的东西,因为它还没有被编译器很好地采用,所以我坚持使用 C++03(这也需要在 PC 以外的其他平台上工作)。还要提一下,在实际代码中我们不使用 uint8_t 等。我们有自己的核心库,提供良好的 unicode 支持。
  • 我们只需要同意不同意这一点的必要性。如果可读性/可导航性是问题,也许你需要一个更好的编辑器。我不认为你所要求的是可能的。无论如何,严格来说,由于缺少外部模板,您的解决方案在 C++11 之前都不是很便携。

标签: c++ file templates split instantiation


【解决方案1】:

您正在尝试做的事情称为显式实例化,正确的语法如下:

template class Example<uint8_t>;
template class Example<uint16_t>;
template class Example<uint32_t>;

如果您确实需要将这些方法区分为单独的文件,我将为上面的代码创建一个文件example_instances.cpp,以便在源中只包含一次以便更好地管理。代码将按以下方式组织:

example.h

template <typename T>
class Example
{
public:
  void test1();
  void test2();
};

example_test1.cpp

#include "example.h"

template <typename T>
void Example::test1()
{
  ...
}

#include "example_instances.cpp"

example_test2.cpp

#include "example.h"

template <typename T>
void Example::test2()
{
  ...
}

#include "example_instances.cpp"

如果不鼓励您包含 .cpp 文件,请将实例放入单独的头文件中。但是,与常见的头文件 (explicit instantiation of function template fails (g++)) 不同,这应该包含在 实现之后。

【讨论】:

  • 我试图将它们分开的原因是,它们需要许多特定于该函数的辅助类和函数,而其他任何人都无法从它们中受益。这就是为什么我想将它们分离为自己的翻译单元并为助手提供内部链接以更好地封装(和可读性)。所以我会有类似的东西,ClassName.h、ClassName.cpp、ClassName_ComplexMethod1.cpp、ClassName_ComplexMethod2.cpp。这是我们常用的编程实践。
  • @Venom 好的,我已经更新了。它应该可以工作,但我没有测试过这种方式。
【解决方案2】:

所以你正在尝试做编译器的工作。如果没有调用,就没有模板类的成员函数的实例化。所以在不同的翻译单元中定义它们是没有用的。编译器在没有你的情况下完成它并且比你更好。我的建议是将所有代码放入头文件中。

【讨论】:

  • 不是没用。它节省了大量编译时间,并防止将类与不应该用作副作用的类型一起使用。如果它没用,它就不会在 C++ 标准中。
  • 试着想一想您可能想要使用此代码的第三个翻译单元。你会怎么做?很难维护这样的代码。模板导出在标准中但是没用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
  • 2015-10-23
  • 2019-09-21
相关资源
最近更新 更多