7

なぜこれが機能するのですか?

同様のSOの質問が表示されますが、誰かがそれをより詳細に説明できますか? 特に、この動作は標準によって保護されていますか?

ああ

#ifndef I_H_
#define I_H_

typedef void (*FuncPtr)();

template<typename T>
void FuncTemplate() {}

class C {};

#endif

a.cc

#include "i.h"

FuncPtr a() {
  return &FuncTemplate<C>;
}

b.cc

#include "i.h"

FuncPtr b() {
  return &FuncTemplate<C>;
}

m.cc

#include <iostream>

#include "i.h"

FuncPtr a();
FuncPtr b();

int main() {
  std::cout << (a() == b() ? "equal" : "not equal") << std::endl;

  return 0;
}

それで

$ g++ -c -o a.o a.cc
$ g++ -c -o b.o b.cc
$ g++ -c -o m.o m.cc
$ g++ a.o b.o m.o -o prog
$ ./prog
equal

-Wall -Wextra -Werror -ansiすべてのg++呼び出しに投げると、同じ結果が得られます。

私の(単純な)理解では、とFuncTemplateの各コンパイル単位で 1 回インスタンス化されるため、アドレスはそれぞれ 1 つのコピーを指す必要があります。結局のところ、これらはどのようにして同じになるのでしょうか? また、この動作は移植可能または保護されていますか?a.ob.o

EDIT共有ライブラリのケース:

$ g++ -shared -o liba.so a.cc
$ g++ -shared -o libb.so b.cc
$ g++ -c -o m.o m.cc
$ g++ -L. -la -lb m.o -o prog
$ ./prog
equal
4

2 に答える 2

6

これは、次の 1 つの定義規則でカバーされます。

3.2 1 つの定義規則 [basic.def.odr]

パラグラフ 5:

クラス型 (条項 9)、列挙型 (7.2)、外部リンケージを持つインライン関数 (7.1.2)、クラス テンプレート (条項 14)、非静的関数テンプレート (14.5.6)の複数の定義が存在する可能性があります。 、クラス テンプレートの静的データ メンバー (14.5.1.3)、クラス テンプレートのメンバー関数 (14.5.1.1)、または一部のテンプレート パラメータが指定されていないテンプレートの特殊化 (14.7、14.5.5)定義は別の翻訳単位に表示され、定義が次の要件を満たしていることが条件です。D という名前のエンティティが複数の翻訳単位で定義されている場合、

従わなければならない、またはその未定義の動作に関する基準の完全なリストがあります。上記では、これらは成り立ちます。それで ...

D の定義がこれらの要件をすべて満たす場合、プログラムは D の定義が 1 つしかないかのように動作します。

したがって、技術的には、各翻訳単位に関数のコピーを含めることができます。

最後のフレーズの文言のように見えますが、すべて同じように動作する必要があります。これは、これらのオブジェクトのいずれかのアドレスを取得すると、同じアドレスになる必要があることを意味します。

于 2011-10-06T05:19:53.890 に答える
4

これは、1 つの定義規則に違反しないため、標準で保証されています。本質的に、インライン関数またはテンプレート関数の宣言と定義が複数の翻訳単位で同じである場合、プログラムはその定義が 1 つあるかのように動作し、その定義はそのアドレスに拡張されます。テンプレート クラスの静的メンバーに関する別の質問に対する私の回答を参照してください。

標準の関連セクションについては、次の[basic.def.odr]とおりです。

... D の定義がこれらすべての要件を満たす場合、プログラムは D の定義が 1 つしかないかのように動作します。D の定義がこれらの要件を満たさない場合、動作は未定義です。

于 2011-10-06T05:19:36.603 に答える