J'essaie de comprendre les extraits de code suivants
Extrait # 1
template <typename T>
struct A
{
static constexpr int VB = T::VD;
};
struct B : A<B>
{
};
Ni gcc9 ni clang9 ne génèrent d'erreur ici.
Q. Pourquoi ce code est-il compilé? N'instancions-nous pas A<B>
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?
Extrait # 2
template <typename T>
struct A
{
static constexpr auto AB = T::AD; // <- No member named AD in B
};
struct B : A<B>
{
static constexpr auto AD = 0xD;
};
Dans ce cas, gcc9 compile bien mais clang9 renvoie une erreur disant "Aucun membre nommé AD dans B".
Q. Pourquoi compile-t-il avec gcc9 / pourquoi ne compile-t-il pas avec clang9?
Extrait # 3
template <typename T>
struct A
{
using TB = typename T::TD;
};
struct B : A<B>
{
using TD = int;
};
Ici, clang9 et gcc9 génèrent une erreur. gcc9 indique "utilisation non valide de type incomplet 'struct B'".
Q. Si la structure B est incomplète ici, pourquoi ne l'est-elle pas dans l'extrait de code # 2?
Drapeaux compilateur utilisé: -std=c++17 -O3 -Wall -Werror
. Merci d'avance!!!
la source
struct B
instanciationA
avecB
?B
est incomplet ... MaisRéponses:
Je crois que cela se résume essentiellement à [temp.inst] / 2 (c'est moi qui souligne):
et [temp.inst] / 9
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
Vous instanciez
A<B>
. Mais l'instanciation instancieA<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
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
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 deA<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 erreurNo 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…la source
constexpr
membre de données statiques n'était qu'une déclaration. C ++ 17 a gagné desinline
variables etconstexpr
impliqueinline
, ce qui fait de la déclaration de membre de données statiques internes une définition.auto
cas, la règle dit que la déclaration doit être une déclaration d'initialisation. Cela ne peut être le cas que si l'on sait que la déclaration est une définition (pour autant que je sache ... je suis hors du pays des avocats depuis un certain temps). Dans le passé, il y avait un cas similaire et eel.is/c++draft/temp.inst#2.sentence-3 a été ajouté, où une déclaration qui est une définition est instanciée comme "étant connue pour être une définition" sans réellement instancier la définition.