¿Qué significa “usar ODR” algo?

92

Esto acaba de surgir en el contexto de otra pregunta .

Aparentemente, las funciones miembro en las plantillas de clase solo se instancian si se utilizan ODR. ¿Alguien podría explicar qué significa eso exactamente? El artículo de Wikipedia sobre la regla de una definición (ODR) no menciona el " uso de ODR ".

Sin embargo, el estándar lo define como

Una variable cuyo nombre aparece como una expresión potencialmente evaluada se usa odr a menos que sea un objeto que satisfaga los requisitos para aparecer en una expresión constante (5.19) y se aplique inmediatamente la conversión de lvalor a rvalue (4.1).

en [basic.def.odr].

Editar: Aparentemente, esta es la parte incorrecta y todo el párrafo contiene múltiples definiciones para diferentes cosas. Este podría ser el relevante para la función de miembro de la plantilla de clase:

Una función no sobrecargada cuyo nombre aparece como una expresión potencialmente evaluada o un miembro de un conjunto de funciones candidatas, si se selecciona mediante la resolución de sobrecarga cuando se hace referencia a ella desde una expresión potencialmente evaluada, se utiliza odr, a menos que sea un virtual puro función y su nombre no está calificado explícitamente.

Sin embargo, no entiendo cómo funciona esta regla en varias unidades de compilación. ¿Se crean instancias de todas las funciones miembro si instancia explícitamente una plantilla de clase?

Sarien
fuente
2
Tenga en cuenta que [basic.def.odr] / 6 se aplica a las funciones miembro de las plantillas de clase "Puede haber más de una definición [...]"
dyp
3
"¿Se crean instancias de todas las funciones miembro si instancia explícitamente una plantilla de clase?" Sí, consulte [temp.explicit] / 8 + 9
dyp

Respuestas:

71

Es solo una definición arbitraria, utilizada por el estándar para especificar cuándo debe proporcionar una definición para una entidad (en lugar de solo una declaración). El estándar no dice solo "usado", porque esto se puede interpretar de manera diversa según el contexto. Y algún uso de ODR no corresponde realmente a lo que uno asociaría normalmente con "uso"; por ejemplo, una función virtual siempre se utiliza con ODR a menos que sea pura, incluso si no se llama en ningún lugar del programa.

La definición completa se encuentra en §3.2 , segundo párrafo, aunque contiene referencias a otras secciones para completar la definición.

Con respecto a las plantillas, el uso de ODR es solo una parte de la cuestión; la otra parte es la instanciación. En particular, §14.7 cubre cuándo se crea una instancia de una plantilla. Pero los dos están relacionados: mientras que el texto en §14.7.1 (instanciación implícita) es bastante largo, el principio básico es que una plantilla solo se instanciará si se usa, y en este contexto, usado significa ODR-usado. Por lo tanto, una función miembro de una plantilla de clase solo se instanciará si se llama, o si es virtual y se instancia la clase en sí. El estándar en sí cuenta con esto en muchos lugares: los std::list<>::sortusos <en los elementos individuales, pero puede instanciar una lista sobre un tipo de elemento que no es compatible <, siempre que no lo invoque sort.

James Kanze
fuente
¿Podría el uso de ODR superponerse con "provisionales materializados"?
v.oddou
23

En palabras simples, odr-used significa que algo (variable o función) se usa en un contexto en el que la definición debe estar presente.

p.ej,

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

Tenga en cuenta que el push_back anterior pasó en MSVC 2013, este comportamiento no es un cumplimiento estándar, tanto gcc 4.8.2 como clang 3.8.0 fallaron, el mensaje de error es: referencia indefinida a `K :: g_x '

Zhaorufei
fuente
¿Es posible utilizar odr un miembro de datos estáticos como vi.push_back( F::g_x );en c ++?
Rankaba
Pero también se podría pasar un rvalue a const int&? ¿Podría el miembro const estático ser considerado como rvalue?
scottxiao
8
+1 para la oración de apertura sucinta: "En palabras simples, odr-used significa que algo (variable o función) se usa en un contexto donde la definición debe estar presente".
Paul Masri-Stone
1
No entiendo cómo compila ese código. ¿Están en la misma TU ?. Si es así, F :: g_x ya se ha definido antes push_back, por supuesto que pasará. ¿No es así?
Lewis Chan
1
@bigxiao " también se podría pasar un rvalue " Sí, y el compilador crea un objeto temporal y la referencia se vincula a ese objeto. OTOH al pasar un lvalue, eso significa pasar ese objeto al que se refiere la evaluación del lvalue: cuando pasa un lvalue, puede esperar que el parámetro en la función se refiera al objeto correcto. El compilador no creará un archivo temporal. Si quieres un temporal, haz uno con operator+.
curioso