Eu acredito que estes se resumem a [temp.inst] / 2 (grifo meu):
A instanciação implícita de uma especialização de modelo de classe causa a instanciação implícita das declarações, mas não das definições , argumentos padrão ou noexcept-specifiers das funções de membro da classe, classes de membros, enumerações de membros com escopo, membros de dados estáticos , modelos de membros e amigos; [...]
e [temp.inst] / 9
Uma implementação não deve instanciar implicitamente […] um membro de dados estáticos de um modelo de classe […], a menos que tal instanciação seja necessária.
A redação do padrão referente à instanciação implícita de modelos deixa muitos detalhes abertos à interpretação. Em geral, parece-me que você simplesmente não pode confiar em partes de um modelo que não são instanciadas, a menos que a especificação o diga explicitamente. Portanto:
Snippet # 1
P. por que esse código é compilado? Não estamos instanciando A ao herdar de B? Não há VD em B, então o compilador não deve lançar um erro aqui?
Você está instanciando A<B>
. Mas a instanciação A<B>
apenas instancia as declarações, não as definições de seus membros de dados estáticos.VB
nunca é usado de uma maneira que exija uma definição para existir. O compilador deve aceitar esse código.
Snippet # 2
P. Por que ele compila com o gcc9 / por que não compila com o clang9?
Conforme apontado por Jarod42, a declaração de AB
contém um tipo de espaço reservado. Parece-me que a redação do padrão não é muito clara sobre o que deveria acontecer aqui. A instanciação da declaração de um membro de dados estático que contém um tipo de espaço reservado aciona a dedução do tipo de espaço reservado e, portanto, constitui um uso que requer a definição do membro de dados estáticos? Não consigo encontrar uma redação no padrão que diga claramente sim ou não a isso. Assim, eu diria que as duas interpretações são igualmente válidas aqui e, portanto, o GCC e o clang estão certos ...
Snippet # 3
Q. Se a estrutura B está incompleta aqui, por que não está incompleta no trecho 2?
Um tipo de classe está completo apenas no ponto em que você alcança o fechamento }
do especificador de classe [class.mem] / 6 . Portanto, B
fica incompleto durante a instanciação implícita de A<B>
em todos os seus snippets. Isso é irrelevante para o snippet nº 1. No Snippet # 2, o clang causou um erro No member named AD in B
como resultado. Semelhante ao caso do Snippet # 2, não consigo encontrar quando exatamente as declarações de alias de membros seriam instanciadas. No entanto, diferentemente da definição de membros de dados estáticos, não há texto para impedir explicitamente a instanciação de declarações de alias de membro durante a instanciação implícita de um modelo de classe. Assim, eu diria que o comportamento do GCC e do clang é uma interpretação válida do padrão neste caso ...
struct B
instanciadoA
comB
?