guide - template function c++
En la declaración “std:: vector<X> f();”, ¿es “std:: vector<X>” una instanciación? (2)
§ 14.7.1 / 1 Creación de instancias implícita [temp.inst]
A menos que una especialización de plantilla de clase haya sido explícitamente instanciada (14.7.2) o explícitamente especializada (14.7.3), la especialización de plantilla de clase se crea implícitamente cuando se hace referencia a la especialización en un contexto que requiere un tipo de objeto completamente definido o cuando la integridad Del tipo de clase afecta a la semántica del programa. La creación de instancias implícita de una especialización de plantilla de clase provoca la creación de instancias implícita de las declaraciones, pero no de las definiciones o argumentos predeterminados, de las funciones de miembro de clase, las clases de miembro, los miembros de datos estáticos y las plantillas de miembro; y provoca la creación de instancias implícitas de las definiciones de uniones anónimas miembros. A menos que un miembro de una plantilla de clase o una plantilla de miembro haya sido explícitamente instanciado o explícitamente especializado, la especialización del miembro se crea implícitamente cuando se hace referencia a la especialización en un contexto que requiere que exista la definición del miembro; en particular, la inicialización (y cualquier efecto secundario asociado) de un miembro de datos estáticos no se produce a menos que el miembro de datos estáticos se use de una manera que requiera que exista la definición del miembro de datos estáticos.
§ 8.3.5 / 9 Funciones [dcl.fct]
Los tipos no se definirán en tipos de retorno o parámetros. El tipo de un parámetro o el tipo de retorno para una definición de función no será un tipo de clase incompleta (posiblemente con calificación CV) a menos que la definición de la función esté anidada dentro de la especificación de miembro para esa clase (incluidas las definiciones en clases anidadas definidas dentro de la clase ).
§ 3.1 / 2 Declaraciones y definiciones [basic.def]
Una declaración es una definición a menos que declare una función sin especificar el cuerpo de la función (8.4), contiene el especificador externo (7.1.1) o una especificación de vinculación25 (7.5) y ni un inicializador ni un cuerpo de función, declara una miembro de datos estáticos en una definición de clase (9.4), es una declaración de nombre de clase (9.1), es una declaración de enumeración opaca (7.2), o es una declaración typedef (7.1.3), una declaración de uso ( 7.3.3), una declaración-declaración-estática (Cláusula 7), una declaración-atributo (Cláusula 7), una declaración-vacía (Cláusula 7) o una directiva using (7.3.4).
Solo se crea una instancia si se requiere . No pude encontrar una definición clara en ninguna parte, pero la segunda cita dice que esas declaraciones no son definiciones, que a mí me parece lo mismo.
El estándar de lenguaje C ++ establece lo siguiente en relación con los componentes de la plantilla en la Biblioteca estándar:
Los efectos no están definidos ... si se usa un tipo incompleto como argumento de plantilla al crear una instancia de un componente de plantilla, a menos que se permita específicamente para ese componente (C ++ 11 §17.6.4.8 / 2).
¿Causa lo siguiente la creación de instancias de la plantilla de clase std::vector
?
class X;
std::vector<X> f(); // Declaration only; we will define it when X is complete
Para preguntarlo de otra manera, en la declaración de función std::vector<X> f();
, es std::vector
instanciado con el argumento X
? O bien, ¿no se crea una instancia de std::vector<X>
hasta que f()
se usa o define odr?
Del mismo modo, ¿la siguiente causa causa la creación de la plantilla de clase std::vector
?
class X;
typedef std::vector<X> XVector; // We will complete X before we use XVector
Mientras uso std::vector
en estos ejemplos, la pregunta se aplica igualmente a todas las plantillas.
No, no crea una instancia de la plantilla. La respuesta de Mooing Duck proporciona todas las citas necesarias, pero aquí hay un análisis.
La creación de instancias, de forma predeterminada, no puede ocurrir si no existe nada que requiera un tipo completamente definido (§14.7.1 / 1). Las definiciones de funciones requieren específicamente tipos completos (§8.3.5 / 9), pero la pregunta es si alguna otra parte de la norma también requiere esto para otras declaraciones.
Pero hay una excepción especial para las definiciones, que revela que las declaraciones sin definición realmente son diferentes:
El tipo de un parámetro o el tipo de retorno para una definición de función no será un tipo de clase incompleta (posiblemente con calificación CV) a menos que la definición de la función esté anidada dentro de la especificación de miembro para esa clase (incluidas las definiciones en clases anidadas definidas dentro de la clase ).
¿Qué tienen de especial las definiciones de funciones dentro de las especificaciones de los miembros? Debido a que una especificación de miembro no puede declarar la misma función dos veces (§9.2 / 1), y los cuerpos de función de miembro se procesan después de todas las declaraciones de miembros (§3.3.7 / 1.1). Esencialmente, una definición de función miembro anidada se trata como una declaración durante la primera pasada, y luego una definición una vez que se ha procesado la especificación completa del miembro, y la clase está completa (§9.2 / 2). Y §8.3.5 / 9 especifica que una clase incompleta es permisible para ese primer paso, pero no el segundo.
Es bastante oneroso realizar una búsqueda exhaustiva y definitiva de las reglas del Estándar para las declaraciones de funciones y las instancias. Pero este ejemplo, aunque limitado a las funciones de los miembros y la integridad del tipo envolvente, puede extenderse razonablemente a otras funciones y tipos. En cualquier caso, es bastante buena evidencia de una distinción.