c++ - 带有模板的目标文件如何链接在一起

标签 c++ templates linker

假设我们有三个 .h文件:

f.h :

template <typename T> class Class {public: Class() {} T id(T x) { return x; }};

g.h :

template <typename T> class Class {public: Class() {} T id(T x) { return x + 100; }};

h.h :

template <typename T> class Class {public: Class(); T id(T x); };

现在,我们还有三个.cpp文件:

f.cpp :

#include "f.h"
int f(int x) { Class<int> t; return t.id(x); }

g.cpp :

#include "g.h"
int g(int x) { Class<int> t; return t.id(x);  }

h.cpp :

#include "h.h"
int h(int x) { Class<int> t; return t.id(x); }

编译它们给我们 f.o , g.oh.o .现在让我们加入这个 main.cpp :

#include <stdio>

extern int f(int);
extern int g(int);
extern int h(int);

int main() {
   std::cout << f(1) << std::endl;
   std::cout << g(2) << std::endl;
   std::cout << h(3) << std::endl;
}

开始吧 g++ main.cpp f.o g.o h.o .现在真正让我吃惊的是:因为那三个 .o文件包含三个不同的定义 int Class<int>::id(int) ,我预计会出现链接错误。然而,我得到的是一个有效的 a.out , 打印 1 2 3 .如果我重新订购 .o命令中的文件,它将打印101 102 103 .

现在是实际问题:在这种情况下,链接器究竟是如何执行链接的?它如何计算出 Class<int> 的实例化?保留什么和扔掉什么?为什么它不提示多个定义?

nm实用程序为 nm f.o g.o h.o 提供以下输出:

f.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 t .text$_ZN5ClassIiE2idEi
00000000 t .text$_ZN5ClassIiEC1Ev
00000000 T __Z1fi
00000000 T __ZN5ClassIiE2idEi
00000000 T __ZN5ClassIiEC1Ev

g.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 t .text$_ZN5ClassIiE2idEi
00000000 t .text$_ZN5ClassIiEC1Ev
00000000 T __Z1gi
00000000 T __ZN5ClassIiE2idEi
00000000 T __ZN5ClassIiEC1Ev

h.o:
00000000 b .bss
00000000 d .data
00000000 d .eh_frame
00000000 t .text
00000000 T __Z1hi
         U __ZN5ClassIiE2idEi
         U __ZN5ClassIiEC1Ev

很明显,f.og.o两个导出符号 __ZN5ClassIiE2idEi , 和 h.o导入此符号(大写字母表示外部链接)。它不会导致错误。为什么?

最佳答案

这个问题实际上是众所周知的:您违反了 ODR。由于模板的性质,编译器和链接器不会注意到这一点。发生的情况如下:

链接器假定没有违反 ODR,因此可以自由使用模板的任何实例化(也就是具有相同参数的模板的所有实例化导致完全相同的结果)正在生成的代码)。只要您不违反 ODR,这个系统就有意义。

现在在您的情况下,链接器选择使用它获得的第一个实例化,这导致结果取决于链接的顺序。

关于c++ - 带有模板的目标文件如何链接在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14458830/

相关文章:

c++ - 检查是否安装了 Windows 服务? (C++)

C++:在指针集中查找

c++ - Leetcode-167:两个和II-输入数组已排序

c++ - 如何在C++中实现不同列数据类型的数据表

C++ 函数模板,体系结构的 undefined symbol

c++ - 静态链接库

c++ - 如何用STL编写仿函数?

c++ - 为什么在限定的依赖名称之前需要关键字 "typename",而不是在限定的独立名称之前?

c++ - 在模板类中使用非模板函数

模板化虚方法的 C++ 链接器错误