ODR に関する質問はたくさんありますが、探しているものが見つからないので、これが重複していたり、タイトルが不適切だったりしたら申し訳ありません。
次の点を考慮してください。
struct t {t(*id)();};
template<typename T>
t type() {return {type<T>};}
これは、 type ごとに一意の識別子を定義しようとする私の試みを単純化しすぎたものであり、異なるコンパイル ユニット間で一意のままであることを願っています。
T
特に、 のような具象型が与えられ、std::string
2 つの異なるコンパイル単位がヘッダー ファイルに上記のコードを含むと仮定すると、次の式が必要です。
type<T>().id
両方の単位で( type の) 同じ値を取るため、t(*)()
type の一意の識別子として機能しT
ます。
値は関数のアドレスなtype<T>
ので、問題はプログラム内type<T>
で一意の関数が一定義規則で保証されているかどうかです。iso 3.2/3 は言う
すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。
どこで 3.2/2
名前が潜在的に評価される式または [...] として表示されるオーバーロードされていない関数は、[...] でない限り、odr で使用されます。
アドレスが取得された場合、関数は非インラインであると想定します(ただし、標準では見つかりません)。
iso 3.2/5 には多くの例外がリストされていますが、関数への唯一の参照は
外部リンケージを持つインライン関数、[...]、非静的関数テンプレート、[...]、クラス テンプレートのメンバー関数、または一部のテンプレート パラメーターが指定されていないテンプレートの特殊化 [...]
ここではそうではないようです。
検証可能な例では、複数のファイルが必要になります。実際、 Dieter Lückingによって失敗したと主張されている例が示されていますが、私の場合は失敗していません (これを「保証」とは見なしません)。
それで、これはうまくいくでしょうか?