何かを「ODR使用」するとはどういう意味ですか?


92

これは、別の質問のコンテキストで発生しました。

どうやら、クラステンプレートのメンバー関数は、ODRで使用されている場合にのみインスタンス化されます。誰かがそれが正確に何を意味するのか説明できますか?一つの定義規則(ODR)上のWikipediaの記事は「言及していないODR-使用を」。

ただし、規格では次のように定義されています

名前が潜在的に評価される式として表示される変数は、定数式(5.19)に表示されるための要件を満たし、左辺値から右辺値への変換(4.1)がすぐに適用されるオブジェクトでない限り、odrで使用されます。

[basic.def.odr]で。

編集:どうやらこれは間違った部分であり、段落全体にさまざまなものの複数の定義が含まれています。これは、クラステンプレートメンバー関数に関連するものである可能性があります。

オーバーロードされていない関数の名前が、評価される可能性のある式または候補関数のセットのメンバーとして表示される場合、評価される可能性のある式から参照されたときにオーバーロード解決によって選択された場合、純粋仮想関数でない限り、odrが使用されます。関数とその名前は明示的に修飾されていません。

しかし、このルールが複数のコンパイルユニットでどのように機能するのかわかりません。クラステンプレートを明示的にインスタンス化すると、すべてのメンバー関数がインスタンス化されますか?


2
[basic.def.odr] / 6は、クラステンプレートのメンバー関数に適用されることに注意してください。「複数の定義が存在する可能性があります[...]」
dyp 2013年

3
「クラステンプレートを明示的にインスタンス化した場合、すべてのメンバー関数がインスタンス化されますか?」はい、[temp.explicit] / 8 + 9
dyp 2013年

回答:


71

これは単なる任意の定義であり、(単なる宣言ではなく)エンティティの定義をいつ提供する必要があるかを指定するために標準で使用されます。これは文脈に応じて多様に解釈できるため、規格では「使用済み」とだけは述べていません。また、一部のODRの使用は、通常「使用」に関連付けられるものと実際には対応していません。たとえば、仮想関数は、プログラム内のどこでも実際に呼び出されていなくても、純粋でない限り常にODRで使用されます。

完全な定義は§3.2の2番目の段落にありますが、これには定義を完了するための他のセクションへの参照が含まれています。

テンプレートに関しては、ODRの使用は問題の一部にすぎません。他の部分はインスタンス化です。特に、§14.7はテンプレートがインスタンス化されるタイミングをカバーしています。ただし、この2つは関連しています。§14.7.1(暗黙のインスタンス化)のテキストはかなり長いですが、基本的な原則は、テンプレートは使用された場合にのみインスタンス化されるということです。このコンテキストでは、使用されるとはODR使用を意味します。したがって、クラステンプレートのメンバー関数は、呼び出された場合、または仮想でクラス自体がインスタンス化された場合にのみインスタンス化されます。標準自体は、多くの場所でこれに依存しています。個々の要素でのstd::list<>::sort使用<ですが、それを<呼び出さない限り、サポートされていない要素タイプでリストをインスタンス化できますsort


ODRの使用は「具体化された一時的」と重複する可能性がありますか?
v.oddou

23

簡単に言うと、odr-usedは、何か(変数または関数)がその定義が存在しなければならないコンテキストで使用されることを意味します。

例えば、

struct F {
   static const int g_x = 2;
};

int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
                             // so it's OK without the definition of g_x

vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
                             // a const lvalue, so it's definition must be present

上記のpush_backがMSVC2013で渡されたことに注意してください。この動作は標準に準拠しておらず、gcc4.8.2とclang3.8.0の両方が失敗しました。エラーメッセージは次のとおりです。`K:: g_x 'への未定義の参照


vi.push_back( F::g_x );c ++のように静的データメンバーをodr-useすることは可能ですか?
ランカバ2017年

しかし、右辺値を次のように渡すこともconst int&できますか?静的constメンバーを右辺値として激怒させることはできますか?
scottxiao

8
簡潔な冒頭の文の+1:「簡単に言うと、odr-usedは、何か(変数または関数)が、その定義が存在しなければならないコンテキストで使用されることを意味します。」
Paul Masri-Stone

1
そのコードをどのようにコンパイルするのかわかりません。それらは同じTUにありますか?もしそうなら、F :: g_xは以前push_backにすでに定義されており、もちろん合格します。そうですね。
ルイスチャン

1
@bigxiao "右辺値を渡すこともできます"はい、一時オブジェクトがコンパイラによって作成され、参照がそのオブジェクトにバインドされます。左辺値を渡すときのOTOHは、左辺値の評価によって参照されるオブジェクトを渡すことを意味します。左辺値を渡すとき、関数のパラメーターが正しいオブジェクトを参照することを期待できます。コンパイラは一時的なものを作成しません。一時的なものが必要な場合は、で作成してくださいoperator+
curiousguy 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.