Was bedeutet es, etwas „ODR-zu verwenden“?


89

Dies kam gerade im Zusammenhang mit einer anderen Frage auf .

Anscheinend werden Mitgliedsfunktionen in Klassenvorlagen nur instanziiert, wenn sie ODR-verwendet werden. Könnte jemand erklären, was genau das bedeutet. Der Wikipedia-Artikel über One Definition Rule (ODR) erwähnt " ODR-Verwendung " nicht.

Der Standard definiert es jedoch als

Eine Variable, deren Name als potenziell ausgewerteter Ausdruck angezeigt wird, wird odr verwendet, es sei denn, es handelt sich um ein Objekt, das die Anforderungen für das Erscheinen in einem konstanten Ausdruck (5.19) erfüllt, und die Konvertierung von Wert zu Wert (4.1) wird sofort angewendet.

in [basic.def.odr].

Bearbeiten: Anscheinend ist dies der falsche Teil und der gesamte Absatz enthält mehrere Definitionen für verschiedene Dinge. Dies könnte für die Funktion der Klassenvorlagenmitglieder relevant sein:

Eine nicht überladene Funktion, deren Name als potenziell ausgewerteter Ausdruck oder Mitglied einer Reihe von Kandidatenfunktionen angezeigt wird, wird odr-verwendet, sofern es sich nicht um eine reine virtuelle Funktion handelt, wenn sie durch Überlastungsauflösung ausgewählt wird, wenn auf einen potenziell ausgewerteten Ausdruck verwiesen wird Funktion und ihr Name ist nicht explizit qualifiziert.

Ich verstehe jedoch nicht, wie diese Regel über mehrere Kompilierungseinheiten hinweg funktioniert. Werden alle Elementfunktionen instanziiert, wenn ich eine Klassenvorlage explizit instanziiere?


2
Beachten Sie, dass [basic.def.odr] / 6 für Elementfunktionen von Klassenvorlagen gilt. "Es kann mehr als eine Definition geben [...]"
dyp

3
"Werden alle Mitgliedsfunktionen instanziiert, wenn ich eine Klassenvorlage explizit instanziiere?" Ja, siehe [temp.explicit] / 8 + 9
dyp

Antworten:


70

Es ist nur eine willkürliche Definition, die vom Standard verwendet wird, um anzugeben, wann Sie eine Definition für eine Entität angeben müssen (im Gegensatz zu nur einer Deklaration). Der Standard sagt nicht nur "verwendet", da dies je nach Kontext unterschiedlich interpretiert werden kann. Und manche ODR-Nutzung entspricht nicht wirklich dem, was man normalerweise mit "Nutzung" assoziieren würde; Beispielsweise wird eine virtuelle Funktion immer ODR-verwendet, es sei denn, sie ist rein, auch wenn sie an keiner Stelle im Programm aufgerufen wird.

Die vollständige Definition befindet sich in §3.2 , zweiter Absatz, obwohl dieser Verweise auf andere Abschnitte enthält, um die Definition zu vervollständigen.

In Bezug auf Vorlagen ist die Verwendung von ODR nur ein Teil der Frage. Der andere Teil ist die Instanziierung. §14.7 behandelt insbesondere, wann eine Vorlage instanziiert wird. Die beiden hängen jedoch zusammen: Während der Text in §14.7.1 (implizite Instanziierung) ziemlich lang ist, besteht das Grundprinzip darin, dass eine Vorlage nur dann instanziiert wird, wenn sie verwendet wird, und in diesem Zusammenhang bedeutet verwendet ODR-verwendet. Daher wird eine Elementfunktion einer Klassenvorlage nur instanziiert, wenn sie aufgerufen wird oder wenn sie virtuell ist und die Klasse selbst instanziiert wird. Der Standard selbst zählt an vielen Stellen darauf: die std::list<>::sortVerwendung <der einzelnen Elemente, aber Sie können eine Liste über einen Elementtyp instanziieren, der nicht unterstützt wird <, solange Sie ihn nicht aufrufen sort.


Könnte sich die ODR-Nutzung mit "materialisierten Provisorien" überschneiden?
v.oddou

20

Im Klartext bedeutet odr-used, dass etwas (Variable oder Funktion) in einem Kontext verwendet wird, in dem die Definition vorhanden sein muss.

z.B,

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

Beachten Sie, dass der obige Push_back in MSVC 2013 übergeben wurde. Dieses Verhalten entspricht nicht der Standardkonformität. Sowohl gcc 4.8.2 als auch clang 3.8.0 sind fehlgeschlagen. Die Fehlermeldung lautet: undefinierter Verweis auf `K :: g_x '


Ist es möglich, ein statisches Datenelement wie vi.push_back( F::g_x );in c ++ odr-zu verwenden ?
Rankaba

Es könnte aber auch ein r-Wert übergeben werden const int&? Könnte das statische const-Element als r-Wert eingestuft werden?
Scottxiao

6
+1 für den prägnanten Eröffnungssatz: "Im Klartext bedeutet odr-used, dass etwas (Variable oder Funktion) in einem Kontext verwendet wird, in dem die Definition vorhanden sein muss."
Paul Masri-Stone

1
Ich verstehe nicht, wie Sie diesen Code kompilieren. Sind sie in der gleichen TU? Wenn dies der Fall ist, wurde F :: g_x bereits zuvor definiert push_back, natürlich wird es bestanden. Ist es nicht?
Lewis Chan

1
@bigxiao " ein rWert könnte auch übergeben werden " Ja und ein temporäres Objekt wird vom Compiler erstellt und die Referenz an dieses Objekt gebunden. OTOH beim Übergeben eines l-Werts, dh beim Übergeben des Objekts, auf das sich die Auswertung des l-Werts bezieht: Wenn Sie einen l-Wert übergeben, können Sie erwarten, dass sich der Parameter in der Funktion auf das richtige Objekt bezieht. Der Compiler erstellt keine temporäre. Wenn Sie eine temporäre möchten, machen Sie eine mit operator+.
Neugieriger
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.