Question Sous-classes imbriquées en C ++


J'essaie de créer une classe imbriquée qui est aussi une sous-classe de son parent:

struct X { struct Y : public X {}; };

Malheureusement, cela ne semble pas être autorisé en C ++, car g ++ produit l'erreur

erreur: utilisation invalide de type incomplet 'struct X'

Cependant, mon code actuel a X en tant que classe modélisée:

template<typename T> struct X
{ struct Y : public X {}; };

Je reçois le même message, mais cette fois, il ne s'agit que d'un avertissement:

avertissement: utilisation non valide du type incomplet 'struct X <T>'

Ma question est la suivante: pourquoi le premier cas est-il illégal, alors que le cas des modèles ne fait que donner un avertissement? La version basée sur les modèles fonctionne exactement comme je l’attendais (je peux créer des instances de X<T>::Y, les jeter à X<T>, et ainsi de suite), mais l'avertissement signifie-t-il que je ne devrais pas l'utiliser? Quels problèmes puis-je m'attendre à rencontrer si j'ignore l'avertissement?


12
2018-01-28 14:40


origine


Réponses:


Techniquement, en ce qui concerne le compilateur, la disposition de la base (X) n’a pas besoin d’être connu jusqu’au modèle (X) est instanciée. Et le modèle (X) peut ne pas être istié avant d'être entièrement défini. A quel point sa mise en page est connue.

Le moyen le plus simple d'obtenir une erreur de votre modèle est d'essayer Y à l'intérieur X:

template<typename T> struct X {
    struct Y : public X {};
    Y y;
};

Dans les versions précédentes du complier, il n'y avait pas d'avertissement dans le cas que vous montrez, mais il a été ajouté à un moment donné. Voici une discussion du Bugtracker GCC à savoir si l'avertissement est faux. Il y avait une certaine incertitude quant à savoir si cela était autorisé par la norme, mais leur conclusion était que ce n'est pas autorisé.

Ainsi, aucun des deux cas n'est autorisé par la norme, mais GCC continue à travailler avec ce dernier, car il le peut.

Yam Marcovic montre comment X::Y peut être défini de manière conforme aux normes. Un exemple identique identique est montré dans le gcc bugtracker.


2
2018-01-28 15:24



Pour répondre à la question de base: vous recevez un avertissement car le modèle n'est pas encore instancié, il ne dérange donc personne.

La façon de résoudre ce problème, dans les deux cas, serait de définir X::Y au point où Xla mise en page est déjà connue, et donc Yla mise en page peut être correctement déduite. Vous pourriez faire:

struct X { struct Y; }
struct X::Y {};

9
2018-01-28 14:47