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?
fuente
Respuestas:
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<>::sort
usos<
en los elementos individuales, pero puede instanciar una lista sobre un tipo de elemento que no es compatible<
, siempre que no lo invoquesort
.fuente
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 '
fuente
vi.push_back( F::g_x );
en c ++?const int&
? ¿Podría el miembro const estático ser considerado como rvalue?push_back
, por supuesto que pasará. ¿No es así?operator+
.