Creo que estos esencialmente se reducen a [temp.inst] / 2 (énfasis mío):
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 , argumentos predeterminados o especificadores sin excepción de las funciones de miembros de clase, clases de miembros, enumeraciones de miembros con ámbito, miembros de datos estáticos , plantillas de miembros y amigos; [...]
y [temp.inst] / 9
Una implementación no debe instanciar implícitamente [...] un miembro de datos estáticos de una plantilla de clase [...] a menos que se requiera dicha instanciación.
La redacción de la norma relativa a la creación de instancias de plantilla implícita deja muchos detalles abiertos a interpretación. En general, me parece que simplemente no puede confiar en partes de una plantilla que no se instancian a menos que la especificación lo diga explícitamente. Así:
Fragmento n. ° 1
P. ¿Por qué se compila este código? ¿No estamos creando instancias de A cuando heredamos de B? No hay VD en B, entonces, ¿no debería el compilador arrojar un error aquí?
Estás creando instancias A<B>
. Pero la creación de instancias A<B>
solo crea instancias de las declaraciones, no las definiciones de sus miembros de datos estáticos. VB
nunca se usa de una manera que requiera una definición para existir. El compilador debe aceptar este código.
Fragmento # 2
P. ¿Por qué se compila con gcc9 / por qué no se compila con clang9?
Como señaló Jarod42, la declaración de AB
contiene un tipo de marcador de posición. Me parece que la redacción de la norma no es realmente clara sobre lo que se supone que sucederá aquí. ¿La instanciación de la declaración de un miembro de datos estáticos que contiene un tipo de marcador de posición activa la deducción del tipo de marcador de posición y, por lo tanto, constituye un uso que requiere la definición del miembro de datos estático? No puedo encontrar una redacción en el estándar que diga claramente sí o no a eso. Por lo tanto, diría que ambas interpretaciones son igualmente válidas aquí y, por lo tanto, GCC y clang tienen razón ...
Fragmento # 3
P. Si la estructura B está incompleta aquí, ¿por qué no está incompleta en el fragmento n. ° 2?
Un tipo de clase solo se completa en el punto en el que llega al cierre }
del especificador de clase [class.mem] / 6 . Por lo tanto, B
está incompleto durante la instanciación implícita de A<B>
todos sus fragmentos. Es solo que esto era irrelevante para Snippet # 1. En Snippet # 2, clang te dio un error No member named AD in B
como resultado. Similar al caso del Snippet # 2, no puedo encontrar la redacción sobre cuándo se instanciarían exactamente las declaraciones de alias de miembro. Sin embargo, a diferencia de la definición de miembros de datos estáticos, no existe una redacción para evitar explícitamente la creación de instancias de declaraciones de alias de miembros durante la creación de instancias implícita de una plantilla de clase. Por lo tanto, diría que el comportamiento de GCC y clang es una interpretación válida del estándar en este caso ...
struct B
instanciasA
conB
?