Je crois que cela se résume essentiellement à [temp.inst] / 2 (c'est moi qui souligne):
L'instanciation implicite d'une spécialisation de modèle de classe provoque l'instanciation implicite des déclarations, mais pas des définitions , des arguments par défaut ou des spécificateurs noexcept des fonctions membres de classe, classes membres, énumérations de membres étendues, membres de données statiques , modèles de membres et copains; […]
et [temp.inst] / 9
Une implémentation ne doit pas implicitement instancier […] un membre de données statique d'un modèle de classe […] sauf si une telle instanciation est requise.
Le libellé de la norme concernant l'instanciation implicite de modèles laisse de nombreux détails ouverts à l'interprétation. En général, il me semble que vous ne pouvez tout simplement pas compter sur des parties d'un modèle qui ne sont pas instanciées à moins que la spécification ne le dise explicitement. Donc:
Extrait # 1
Q. Pourquoi ce code est-il compilé? N'instancions-nous pas A en héritant de B? Il n'y a pas de VD dans B, donc le compilateur ne devrait-il pas lancer une erreur ici?
Vous instanciez A<B>
. Mais l'instanciation instancie A<B>
uniquement les déclarations, pas les définitions de ses membres de données statiques. VB
n'est jamais utilisé d'une manière qui nécessiterait une définition. Le compilateur doit accepter ce code.
Extrait # 2
Q. Pourquoi compile-t-il avec gcc9 / pourquoi ne compile-t-il pas avec clang9?
Comme l'a souligné Jarod42, la déclaration de AB
contient un type d'espace réservé. Il me semble que le libellé de la norme n'est pas vraiment clair sur ce qui est censé se produire ici. L'instanciation de la déclaration d'un membre de données statique qui contient un type d'espace réservé déclenche-t-elle une déduction de type d'espace réservé et, par conséquent, constitue-t-elle une utilisation qui nécessite la définition du membre de données statique? Je ne trouve pas de libellé dans la norme qui dirait clairement oui ou non. Ainsi, je dirais que les deux interprétations sont également valables ici et, par conséquent, GCC et clang ont tous deux raison…
Extrait # 3
Q. Si la structure B est incomplète ici, pourquoi ne l'est-elle pas dans l'extrait de code # 2?
Un type de classe n'est complet qu'au point où vous atteignez la fermeture }
du spécificateur de classe [class.mem] / 6 . Ainsi, B
est incomplet lors de l'instanciation implicite de A<B>
dans tous vos extraits. C'est juste que cela n'était pas pertinent pour l'extrait de code n ° 1. Dans l'extrait de code n ° 2, clang vous a donné une erreur No member named AD in B
en conséquence. Semblable au cas de l'extrait de code # 2, je ne trouve pas de libellé sur le moment exact où les déclarations d'alias de membre seraient instanciées. Cependant, contrairement à la définition des membres de données statiques, aucun libellé n'est en place pour empêcher explicitement l'instanciation des déclarations d'alias de membre lors de l'instanciation implicite d'un modèle de classe. Ainsi, je dirais que le comportement de GCC et de clang est une interprétation valide de la norme dans ce cas…
struct B
instanciationA
avecB
?