模板实例化对编译持续时间的影响



编写模板类时,我们必须将方法主体内.h文件中(除非在.cpp文件中实例化它们(。我们知道修改内联方法需要重新编译包含它们的单元。这将使编译时间变长。实现模板类的另一种技术是在.cpp文件中实例化它。

文件Test.h

template <typename T>
class Test
{
public:
    T data;
    void func();
};

文件Test.cpp

template <typename T>
void Test<T>::func()
{
}
template class Test<float>; // explicit instantiation

井。这种技术是否有效地减少了func()修改后使用Test<float>的编译时间?

由于成员函数的定义都在 cpp 内部,因此对其他翻译单元不可用,因此这些函数不会被隐式实例化,因此编译代码的成本仅限于单个 cpp。

该方法的问题在于,您将模板的使用限制为为其提供手动实例化的一个或多个类型。外部用户无法为其他类型的实例化它,如果必须这样做,则需要记住手动专用于要使用的每种类型。

还有一种替代方案,成本略高(不多(,但这是通用的,并且比天真的方法编译更快。您可以在标头中提供模板定义,但指示编译器不要为一组常见类型隐式实例化它,然后在单个翻译单元中为其提供手动实例化:

// .h
#ifndef TEST_H
#define TEST_H
template <typename T>
class Test
{
public:
    T data;
    void func() { ... }  // definition here
};
extern template class Test<float>;   // Declare explicit instantiation for float
extern template class Test<int>;     //                                for int
#endif /* TEST_H */
// cpp
#include "test.h"
template class Test<float>;          // explicit instantiation
template class Test<int>;

在此方法中,模板对于用户可能想要使用的任何类型的实例化都是可见的。但是,您明确告诉编译器不要为您提供专用化的已知类型子集执行工作。如果用户想要Test<std::string>那么编译器将隐式实例化它,并且该翻译单元将付出代价。对于仅实例化Test<float>Test<int>或包含标头但根本不实例化模板的翻译单元,将有一些额外的成本(解析器需要处理定义(,但不会产生代码(二进制(,或浪费在优化器和/或链接器丢弃重复符号上的时间。

正如您提到的,它还意味着,如果标头的内容发生更改,则重新编译包含该标头的所有用户代码。

最新更新