Credo che sostanzialmente si riducano a [temp.inst] / 2 (enfasi sulla mia):
L'istanza implicita di una specializzazione del modello di classe provoca l'istanziazione implicita delle dichiarazioni, ma non delle definizioni , degli argomenti predefiniti o degli identificatori noexcept delle funzioni dei membri della classe, delle classi di membri, delle enumerazioni dei membri con ambito, dei membri di dati statici , dei modelli di membri e amici; [...]
e [temp.inst] / 9
Un'implementazione non deve istanziare implicitamente [...] un membro di dati statici di un modello di classe [...] a meno che tale istanza non sia richiesta.
La formulazione nella norma relativa all'istanza implicita del modello lascia molti dettagli aperti all'interpretazione. In generale, mi sembra che semplicemente non si possa fare affidamento su parti di un modello non vengano istanziate a meno che la specifica non lo dica esplicitamente. Così:
Snippet n. 1
D. Perché viene compilato questo codice? Non stiamo istanziando A quando ereditiamo da B? Non c'è VD in B, quindi il compilatore non dovrebbe lanciare un errore qui?
Stai istanziando A<B>
. Ma l'istanza A<B>
non fa che istanziare le dichiarazioni, non le definizioni dei suoi membri di dati statici.VB
non viene mai utilizzato in un modo che richiederebbe l'esistenza di una definizione. Il compilatore dovrebbe accettare questo codice.
Snippet # 2
D. Perché si compila con gcc9 / perché non si compila con clang9?
Come sottolineato da Jarod42, la dichiarazione di AB
contiene un tipo di segnaposto. Mi sembra che la formulazione dello standard non sia davvero chiara su cosa dovrebbe succedere qui. L'istanza della dichiarazione di un membro di dati statici che contiene un tipo di segnaposto attiva la deduzione del tipo di segnaposto e, quindi, costituisce un uso che richiede la definizione del membro di dati statici? Non riesco a trovare una formulazione nello standard che direbbe chiaramente sì o no. Quindi, direi che entrambe le interpretazioni sono ugualmente valide qui e, quindi, GCC e clang hanno entrambi ragione ...
Snippet # 3
D. Se la struttura B è incompleta qui, perché non è incompleta nello snippet # 2?
Un tipo di classe è solo completo nel punto in cui si raggiunge la chiusura }
della classe specificatore [class.mem] / 6 . Pertanto, B
è incompleto durante l'istanza implicita di A<B>
in tutti i frammenti. È solo che ciò era irrilevante per lo snippet n. 1. In Snippet # 2, di conseguenza clang ti ha dato un errore No member named AD in B
. Simile al caso dello snippet n. 2, non riesco a trovare una formulazione su quando verranno istanziate esattamente le dichiarazioni di alias dei membri. Tuttavia, a differenza della definizione di membri di dati statici, non esiste una formulazione per impedire esplicitamente l'istanza delle dichiarazioni di alias dei membri durante l'istanza implicita di un modello di classe. Quindi, direi che il comportamento di GCC e clang è una valida interpretazione dello standard in questo caso ...
struct B
un'istanzaA
conB
?