【问题标题】:Linking/compile time concerning static template libraries关于静态模板库的链接/编译时间
【发布时间】:2012-10-06 17:54:25
【问题描述】:

对于基于模板的类(STL 和 boost)不使用源文件并将实现也放入标题中似乎是一种常见的约定。我认为与头文件和源文件中的声明和实现之间的经典分离相比,这将大大增加编译包含头文件的源文件所需的时间。 The reason why this is done is probably due to the fact that you would have to tell the compiler in the source file which templates to use, which will probably result in a bloated .a file.

假设随着库的增长,链接器也需要更多时间,就编译包含库头文件的源文件所需的时间而言,哪种方法更快?

1。不使用 .cpp 文件并将整个类(包括实现)放入标题中

//foo.hpp
template <class T>
class Foo
{
public:
    Foo(){};
    T bar()
    {
        T* t = NULL;
        //do stuff
        return *t;
    }
};

2。在库本身的源文件中为各种类型显式编译模板

//foo.h
template <class T>
class Foo
{
public:
    Foo(){};
    T bar();
};

//foo.cpp
template <class T>
T Foo<T>::bar()
{
    T* t = NULL;
    //do stuff
    return *t;
}

template class Foo<int>;
template class Foo<float>;
template class Foo<double>;
template class Foo<long long>;

【问题讨论】:

    标签: c++ templates header compilation-time explicit-instantiation


    【解决方案1】:

    模板的关键问题是编译器不知道模板将用于哪些模板参数。编译器知道模板与特定参数集一起使用的唯一时间是当它看到使用的模板并且编译器将在此时实例化模板。因此,代码通常被放入头文件中,因此编译器可以在使用时代表用户实例化模板。

    或者,模板的作者可以告诉编译器模板与特定的模板参数列表一起使用,然后显式地实例化它们。在这种情况下,模板定义可以进入源文件(或者,更有可能是用户通常不包含的特殊标题)。这种方法的问题是模板代码的作者不一定知道需要哪些实例化。

    在 C++ 2011 中也有一个中间立场:可以通过将特化声明为 extern 来告诉编译器某些实例化已经创建。这样,编译器知道它不需要使用某些参数来实例化模板,但如果使用了其他参数,它知道它需要创建它们。例如,标准 C++ 库有std::basic_string,它可以预测charwchar_t 的实例化可能会被使用,并且可以将它们放入库中,将实例化声明为extern。但是,让代码随时可用使得将std::basic_string&lt;user_type&gt; 与用户定义的类型一起使用变得可行。

    展望未来,我们希望得到一个模块系统,但目前没有人真正知道这样的系统应该如何真正工作。对该主题感兴趣的编译器实现者有一个小组来考虑模块,并且像这样的系统可能有助于模板的编译时间。

    【讨论】:

    • 我已经知道大部分了。我只是想知道哪种方法为用户编译和链接所需的时间更少(鉴于我知道需要哪些类型)。
    • 如果您可以避免在多个翻译单元中自动实例化代码,通常使用预实例化模板编译代码会更快,尤其是在使用优化时。链接时间也可能会下降,尽管这在某种程度上取决于链接器。通过将 IOStream 和 locales 库从标头中移出,我可以显着改进编译!不过我没试过用extern模板是否能达到同样的效果。
    【解决方案2】:

    通常,编译器为特定编译单元生成一次代码,然后链接器确保其他编译单元可以访问变量和函数。

    在模板方面,情况不再如此。在实例化模板的具体实例之前,编译器无法为模板生成代码。因此,我们在每个编译单元中实例化模板,而无需复制和粘贴的唯一方法是将所有模板代码放在头文件中。

    然后,链接器还必须能够识别模板并协调同一对象的多个实例。

    C++11 确实对这种可以声明的场景有所帮助:

    template class MyTemplate<MyType>;
    

    在单个 C++ 文件中,然后使用:

    extern template class MyTemplate<MyType>;
    

    后者不会在当前编译单元中实例化模板,而是让链接器链接到已经定义的模板。

    查看here了解更多详情

    【讨论】:

      【解决方案3】:

      已经有两个很好的答案了,我就简单写一下。
      如果没有 具体 类型,就无法编译模板代码,这就是为什么您不能进行经典的“编译和链接”。
      模板函数或类是不完整的,因为并非所有类型都被解析,直到它在代码中的特定用法(某种类型替换模板)。
      为此,模板放在头文件中,不能独立于具体用途进行编译。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-03
        • 1970-01-01
        • 2011-03-05
        • 2020-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多