Cosa significa "utilizzare ODR" qualcosa?


92

Questo è appena emerso nel contesto di un'altra domanda .

Apparentemente le funzioni membro nei modelli di classe vengono istanziate solo se sono utilizzate da ODR. Qualcuno potrebbe spiegare cosa significa esattamente. L' articolo di wikipedia su One Definition Rule (ODR) non menziona "l' uso di ODR ".

Tuttavia lo standard lo definisce come

Una variabile il cui nome appare come un'espressione potenzialmente valutata viene usata odr a meno che non sia un oggetto che soddisfa i requisiti per apparire in un'espressione costante (5.19) e la conversione lvalue-rvalue (4.1) viene immediatamente applicata.

in [basic.def.odr].

Modifica: Apparentemente questa è la parte sbagliata e l'intero paragrafo contiene più definizioni per cose diverse. Questo potrebbe essere quello rilevante per la funzione membro del modello di classe:

Una funzione non sovraccaricata il cui nome appare come un'espressione potenzialmente valutata o un membro di un insieme di funzioni candidate, se selezionata dalla risoluzione dell'overload quando ci si riferisce a un'espressione potenzialmente valutata, viene usata odr, a meno che non sia un puro virtuale funzione e il suo nome non è esplicitamente qualificato.

Tuttavia non capisco, come funziona questa regola su più unità di compilazione? Tutte le funzioni membro vengono istanziate se istanzio esplicitamente un modello di classe?


2
Nota che [basic.def.odr] / 6 si applica alle funzioni membro dei modelli di classe "Può esserci più di una definizione [...]"
dyp

3
"Vengono istanziate tutte le funzioni membro se istanzio esplicitamente un modello di classe?" Sì, vedi [temp.explicit] / 8 + 9
dyp

Risposte:


71

È solo una definizione arbitraria, utilizzata dallo standard per specificare quando è necessario fornire una definizione per un'entità (al contrario di una semplice dichiarazione). Lo standard non dice solo "usato", perché questo può essere interpretato in modo diverso a seconda del contesto. E alcuni utilizzi di ODR non corrispondono realmente a ciò che normalmente si associa all '"uso"; ad esempio, una funzione virtuale è sempre utilizzata da ODR a meno che non sia pura, anche se non viene effettivamente chiamata da nessuna parte nel programma.

La definizione completa è in §3.2 , secondo paragrafo, sebbene questo contenga riferimenti ad altre sezioni per completare la definizione.

Per quanto riguarda i modelli, l'ODR utilizzato è solo una parte della domanda; l'altra parte è l'istanziazione. In particolare, §14.7 copre quando viene creata un'istanza di un modello. Ma i due sono correlati: mentre il testo in §14.7.1 (istanziazione implicita) è abbastanza lungo, il principio di base è che un modello sarà istanziato solo se viene utilizzato, e in questo contesto, usato significa ODR-usato. Pertanto, una funzione membro di un modello di classe verrà istanziata solo se viene chiamata o se è virtuale e viene creata un'istanza della classe stessa. Lo standard stesso conta su questo in molti punti: gli std::list<>::sortusi <sui singoli elementi, ma puoi istanziare un elenco su un tipo di elemento che non supporta <, purché non lo chiami sort.


l'uso di ODR potrebbe sovrapporsi ai "provvisori materializzati"?
v.oddou

23

In parole povere, odr-usato significa che qualcosa (variabile o funzione) viene utilizzato in un contesto in cui la definizione di esso deve essere presente.

per esempio,

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

Nota, il push_back precedente è passato in MSVC 2013, questo comportamento non è conforme allo standard, sia gcc 4.8.2 che clang 3.8.0 non sono riusciti, il messaggio di errore è: riferimento indefinito a `K :: g_x '


È possibile utilizzare odr un membro dati statico come vi.push_back( F::g_x );in c ++?
Rankaba

Ma un rvalue potrebbe anche essere passato a const int&? Il membro const statico potrebbe essere considerato come rvalue?
scottxiao

8
+1 per la frase iniziale succinta: "In parole semplici, odr-usato significa che qualcosa (variabile o funzione) è usato in un contesto in cui la definizione di esso deve essere presente."
Paul Masri-Stone

1
Non capisco come compili quel codice. Sono nella stessa TU?. Se lo sono, F :: g_x è già stato definito in precedenza push_back, ovviamente passerà. Non è vero?
Lewis Chan

1
@ bigxiao " potrebbe anche essere passato un rvalue " Sì e un oggetto temporaneo viene creato dal compilatore e il riferimento è associato a quell'oggetto. OTOH quando si passa un lvalue significa passare quell'oggetto a cui fa riferimento la valutazione di lvalue: quando si passa un lvalue ci si può aspettare che il parametro nella funzione si riferisca all'oggetto corretto. Il compilatore non creerà un file temporaneo. Se vuoi un temporaneo, creane uno con operator+.
Curiousguy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.