c++ - 隐式模板实例化何时发生?

标签 c++

我想知道在以下情况下何时/何处发生隐式模板实例化。

// temp.h
template <typename T>
struct A {
    T value;
}
// foo.h
#include "temp.h"
void foo();
// foo.cpp
#include "foo.h"
void foo() { A<int> _foo; }
// bar.h
#include "temp.h"
void bar();
// bar.cpp
#include "bar.h"
void bar() { A<int> _bar; }
// main.cpp
#include "foo.h"
#include "bar.h"
int main() { foo(); bar(); return 0; }

我认为它发生在 foo() 时被调用是因为它是第一次使用 A<int> , 所以 A<int>foo.o 实现.
而且,当bar()被称为,它链接到 A<int>foo.o .

我说的对吗?或者实例化发生两次?

最佳答案

标准没有说明编译器应该如何隐式实例化模板。

我不确定其他编译器,这就是 g++ 处理它的方式,来自 7.5 Where's the Template? :

Somehow the compiler and linker have to make sure that each template instance occurs exactly once in the executable if it is needed, and not at all otherwise. There are two basic approaches to this problem, which are referred to as the Borland model and the Cfront model.

  • Borland model:

Borland C++ solved the template instantiation problem by adding the code equivalent of common blocks to their linker; the compiler emits template instances in each translation unit that uses them, and the linker collapses them together. The advantage of this model is that the linker only has to consider the object files themselves; there is no external complexity to worry about. The disadvantage is that compilation time is increased because the template code is being compiled repeatedly. Code written for this model tends to include definitions of all templates in the header file, since they must be seen to be instantiated.

  • 前台模特:

The AT&T C++ translator, Cfront, solved the template instantiation problem by creating the notion of a template repository, an automatically maintained place where template instances are stored. A more modern version of the repository works as follows: As individual object files are built, the compiler places any template definitions and instantiations encountered in the repository. At link time, the link wrapper adds in the objects in the repository and compiles any needed instances that were not previously emitted. The advantages of this model are more optimal compilation speed and the ability to use the system linker; to implement the Borland model a compiler vendor also needs to replace the linker. The disadvantages are vastly increased complexity, and thus potential for error; for some code this can be just as transparent, but in practice it can been very difficult to build multiple programs in one directory and one program in multiple directories. Code written for this model tends to separate definitions of non-inline member templates into a separate file, which should be compiled separately.

这就是 g++ 实现它的方式,重点是我的:

G++ implements the Borland model on targets where the linker supports it, including ELF targets (such as GNU/Linux), Mac OS X and Microsoft Windows. Otherwise G++ implements neither automatic model.

就是说:使用 g++,每个翻译单元都会有自己的实例化。在该页面中再次提到它:

..., but each translation unit contains instances of each of the templates it uses. The duplicate instances will be discarded by the linker, but in a large program, this can lead to an unacceptable amount of code duplication in object files or shared libraries.

您选择避免它(当然第一个和最后一个选项是明确的):

  1. Duplicate instances of a template can be avoided by defining an explicit instantiation in one object file, and preventing the compiler from doing implicit instantiations in any other object files by using an explicit instantiation declaration, using the extern template syntax

  2. Compile your template-using code with -frepo. The compiler generates files with the extension .rpo listing all of the template instantiations used in the corresponding object files that could be instantiated there; the link wrapper, collect2, then updates the .rpo files to tell the compiler where to place those instantiations and rebuild any affected object files. The link-time overhead is negligible after the first pass, as the compiler continues to place the instantiations in the same files.

  3. Compile your code with -fno-implicit-templates to disable the implicit generation of template instances, and explicitly instantiate all the ones you use.

关于c++ - 隐式模板实例化何时发生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40603219/

相关文章:

c# - 通过共享内存将数据从 C++ 流式传输到 C#

c++ - R CMD SHLIB 使用 RcppArmadillo 编译错误

C++ 容器-如果为类型定义了运算符<<,则列出成员?

c++ - glUniformMatrix4fv 失败,错误代码为 GL_INVALID_OPERATION

c++ - 根据我对 §3.4.1/8 的解释,这段代码应该可以编译。我错过了什么?

c++ - 如何获取数组元素的地址?

C++ 查找函数编译错误与 std::string

c++ - "Pointer being freed was not allocated"向存储添加元素时

c++ - 读取 16 位 wav 文件并像 Matlab 一样对其进行归一化

C++ GUI 和控制台应用程序