Co to znaczy „używać ODR”?

92

To właśnie pojawiło się w kontekście innego pytania .

Wygląda na to, że funkcje składowe w szablonach klas są tworzone tylko wtedy, gdy są używane przez ODR. Czy ktoś mógłby wyjaśnić, co to dokładnie oznacza. Artykuł Wikipedii na temat reguły jednej definicji (ODR) nie wspomina o „ używaniu ODR ”.

Jednak standard definiuje to jako

Zmienna, której nazwa pojawia się jako wyrażenie potencjalnie wartościowane, jest używana jako odr, chyba że jest obiektem, który spełnia wymagania dotyczące pojawienia się w wyrażeniu stałym (5.19), a konwersja lwartość do rwartości (4.1) jest natychmiast stosowana.

w [basic.def.odr].

Edycja: Najwyraźniej jest to zła część, a cały akapit zawiera wiele definicji różnych rzeczy. To może być odpowiednie dla funkcji składowej szablonu klasy:

Nieprzetężona funkcja, której nazwa pojawia się jako potencjalnie ocenione wyrażenie lub element członkowski zestawu funkcji kandydujących, jeśli zostanie wybrana przez rozpoznanie przeciążenia w przypadku odwołania z potencjalnie ocenianego wyrażenia, jest używana przez ODR, chyba że jest to czysta wirtualna funkcja, a jej nazwa nie jest jawnie kwalifikowana.

Nie rozumiem jednak, jak ta reguła działa w wielu jednostkach kompilacji? Czy instancje wszystkich funkcji składowych są tworzone, jeśli jawnie utworzę wystąpienie szablonu klasy?

Sarien
źródło
2
Zauważ, że [basic.def.odr] / 6 odnosi się do funkcji składowych szablonów klas "Może być więcej niż jedna definicja [...]"
odejdź
3
„Czy tworzone są instancje wszystkich funkcji składowych, jeśli jawnie utworzę instancję szablonu klasy?” Tak, zobacz [temp.explicit] / 8 + 9
dyp

Odpowiedzi:

71

To po prostu dowolna definicja, używana przez standard do określenia, kiedy należy podać definicję jednostki (a nie tylko deklarację). Standard nie mówi tylko „używany”, ponieważ można to interpretować różnie w zależności od kontekstu. A niektóre zastosowania ODR tak naprawdę nie odpowiadają temu, co normalnie kojarzy się z „użyciem”; na przykład funkcja wirtualna jest zawsze używana przez ODR, chyba że jest czysta, nawet jeśli w rzeczywistości nie jest wywoływana nigdzie w programie.

Pełna definicja znajduje się w §3.2 , drugi akapit, chociaż zawiera odniesienia do innych sekcji w celu uzupełnienia definicji.

Jeśli chodzi o szablony, użycie ODR to tylko część pytań; druga część to tworzenie instancji. W szczególności §14.7 dotyczy sytuacji, w których tworzona jest instancja szablonu. Ale oba są powiązane: chociaż tekst w §14.7.1 (niejawna instancja) jest dość długi, podstawową zasadą jest to, że szablon zostanie utworzony tylko wtedy, gdy zostanie użyty, iw tym kontekście użyte oznacza użycie ODR. W związku z tym funkcja składowa szablonu klasy zostanie utworzona tylko wtedy, gdy zostanie wywołana lub jeśli jest wirtualna i zostanie utworzona instancja samej klasy. Sam standard liczy na to w wielu miejscach: std::list<>::sortzastosowania <na poszczególnych elementach, ale możesz utworzyć instancję listy na typie elementu, który nie obsługuje <, o ile go nie wywołujesz sort.

James Kanze
źródło
czy użycie ODR może pokrywać się z „zmaterializowanymi elementami tymczasowymi”?
v.oddou
23

W prostych słowach, odr-used oznacza, że ​​coś (zmienna lub funkcja) jest używane w kontekście, w którym musi istnieć definicja tego.

na przykład,

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

Uwaga, powyższe push_back przekazane w MSVC 2013, to zachowanie nie jest standardową zgodnością, zarówno gcc 4.8.2, jak i clang 3.8.0 nie powiodły się, komunikat o błędzie to: undefined odwołanie do `K :: g_x '

zhaorufei
źródło
Czy można odr używać statycznego elementu członkowskiego danych, takiego jak vi.push_back( F::g_x );w C ++?
Rankaba
Ale wartość r może być również przekazana do const int&? Czy statyczny element stałej stałej może być traktowany jako rvalue?
scottxiao
8
+1 dla zwięzłego zdania otwierającego: „W prostym słowie, odr-used oznacza, że ​​coś (zmienna lub funkcja) jest używane w kontekście, w którym musi istnieć definicja tego”.
Paul Masri-Stone
1
Nie rozumiem, jak kompilujesz ten kod. Czy są w tej samej jednostce tłumaczeniowej? Jeśli tak, F :: g_x zostało już zdefiniowane wcześniej push_back, oczywiście przejdzie. Prawda?
Lewis Chan
1
@bigxiao " można również przekazać rvalue " Tak, a kompilator tworzy obiekt tymczasowy i odwołuje się do tego obiektu. OTOH podczas przekazywania lwartości, co oznacza przekazanie tego obiektu, do którego odwołuje się ocena lwartości: po przekazaniu lwartości można oczekiwać, że parametr w funkcji będzie odnosił się do właściwego obiektu. Kompilator nie utworzy tymczasowego pliku. Jeśli chcesz tymczasowy, zrób taki z operator+.
ciekawy facet