web-dev-qa-db-fra.com

Type incomplet dans le spécificateur de nom imbriqué

J'ai essayé d'utiliser un type incomplet dans le spécificateur de nom imbriqué comme suit:

class A;

int b= A::c; // error: incomplete type ‘A’ used in nested name specifier

class A {
    static const int c=5;
};

Il n'y a rien à dire à ce sujet dans le projet de travail 3.4.3/1 de N3797:

Le nom d'un membre de classe ou d'espace de noms ou d'un énumérateur peut être référencé après que l'opérateur de résolution de portée (5.1) a été appliqué à un spécificateur de nom imbriqué qui désigne sa classe, son espace de noms ou son énumération

Cette implémentation du comportement dépend-elle donc?

34
user2953119

Introduction

Il y a plusieurs endroits dans la norme qui implicitement impliquent que votre code est mal formé, mais la citation ci-dessous parle d'elle-même:

3.3.2p6Point de déclaration[basic.scope.pdecl]

Après le point de déclaration d'un membre de classe, le nom du membre peut être recherché dans le cadre de sa classe.

Le problème avec votre code n'est pas que vous essayez d'atteindre l'intérieur du corps d'un type incomplet, le problème est que vous ne pouvez faire référence qu'à un nom de membre de la classe après il a été déclaré.

Puisque votre déclaration directe (bien sûr) n'introduit aucun membre nommé c , il est mal formé de se référer à un tel nom.


Le diagnostic trompeur ...

Le diagnostic émis par gcc et clang lors de la saisie de votre code est quelque peu trompeur, et honnêtement, je pense qu'un rapport de bogue est en ordre.

foo.cpp:3:8: error: incomplete type 'A' named in nested name specifier


Nous sommes autorisés à nommer un type incomplet dans un spécificateur de nom imbriqué , mais comme dit; nous ne sommes pas autorisés à faire référence à un membre qui n'a pas encore été déclaré.

mal formé:

class X {
  static int a[X::x];        // ill-formed, `X::x` has not yet been declared
  static int const x = 123;
};

légal:

class X {
  int const x = 123;
  int a[X::x]; // legal, `X` is incomplete (since we are still defining it)
               //        but we can still refer to a _declared_ member of it
};
38