次の 3 つの.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これで、次の 3 つのファイルもあります。
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.oおよびが得られh.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。これら 3 つの.oファイルには の 3 つの異なる定義が含まれ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.o、g.o両方とも export symbol__ZN5ClassIiE2idEiとh.oimport this symbol (大文字は外部リンケージを意味します)。そして、それはエラーにつながりません。なんで?