¿Por qué no puedo reenviar-declarar una clase en un espacio de nombres usando dos puntos y coma?

class Namespace::Class; 

¿Por qué tengo que hacer esto ?:

 namespace Namespace { class Class; } 

Usando VC ++ 8.0, el comstackdor emite:

error C2653: ‘Namespace’: no ​​es una clase o nombre de espacio de nombres

Supongo que el problema aquí es que el comstackdor no puede decir si Namespace es una clase o un espacio de nombres. Pero, ¿por qué es importante ya que es solo una statement avanzada?

¿Hay alguna otra forma de reenviar-declarar una clase definida en algún espacio de nombres? La syntax anterior se siente como si estuviera “reabriendo” el espacio de nombres y ampliando su definición. ¿Qué pasa si la Class no se definió realmente en Namespace ? ¿Esto resultaría en un error en algún momento?

Porque no puedes. En lenguaje C ++ los nombres completamente calificados solo se usan para referirse a entidades existentes (es decir, declaradas previamente). No se pueden usar para introducir nuevas entidades.

Y de hecho está “reabriendo” el espacio de nombres para declarar nuevas entidades. Si la clase Class se define más tarde como miembro de un espacio de nombres diferente, es una clase completamente diferente que no tiene nada que ver con la que usted declaró aquí.

Una vez que llega al punto de definir la clase preestablecida, no necesita “volver a abrir” el espacio de nombres nuevamente. Puede definirlo en el espacio de nombres global (o cualquier espacio de nombres que contenga su Namespace ) como

 class Namespace::Class { /* whatever */ }; 

Como se refiere a una entidad que ya ha sido declarada en el espacio de Namespace espacio de Namespace , puede usar el nombre calificado Namespace::Class .

Obtendrá las respuestas correctas, permítame intentar una nueva redacción:

class Namespace::Class;

¿Por qué tengo que hacer esto?

Tienes que hacer esto porque el término Namespace::Class le dice al comstackdor:

… OK, comstackdor. Ve a buscar el espacio de nombre llamado Namespace, y dentro de ese se refieren a la clase llamada Class.

Pero el comstackdor no sabe de lo que está hablando porque no conoce ningún espacio de nombres llamado Namespace . Incluso si hubiera un espacio de nombres llamado Namespace , como en:

 namespace Namespace { }; class Namespace::Class; 

aún no funcionaría, porque no puede declarar una clase dentro de un espacio de nombres desde fuera de ese espacio de nombres. Tienes que estar en el espacio de nombres.

Entonces, de hecho, puede reenviar declarar una clase dentro de un espacio de nombres. Solo haz esto:

 namespace Namespace { class Class; }; 

Supongo que es por la misma razón por la que no puede declarar espacios de nombres nesteds de la siguiente manera:

 namespace Company::Communications::Sockets { } 

y tienes que hacer esto:

 namespace Company { namespace Communications { namespace Sockets { } } } 

Hay muchas respuestas excelentes sobre la lógica implicada en rechazarlo. Solo quiero proporcionar la aburrida cláusula standardese que específicamente lo prohíbe. Esto es válido para C ++ 17 (n4659).

El párrafo en cuestión es [class.name] / 2 :

Una statement que consiste únicamente en un identificador de clave de clase ; es una restatement del nombre en el ámbito actual o una statement directa del identificador como nombre de clase. Introduce el nombre de la clase en el scope actual.

Lo anterior define lo que constituye una statement directa (o statement en rojo de una clase). Básicamente, debe ser uno de class identifier; de class identifier; , struct identifier; o union identifier; donde identifer es la definición léxica común en [lex.name] :

 identifier: identifier-nondigit identifier identifier-nondigit identifier digit identifier-nondigit: nondigit universal-character-name nondigit: one of abcdefghijklm nopqrstuvwxyz ABCDEFGHIJKLM NOPQRSTUVWXYZ _ digit: one of 0 1 2 3 4 5 6 7 8 9 

¿Cuál es la producción del esquema común [a-zA-Z_][a-zA-Z0-9_]* que todos estamos familiarizados? Como puede ver, esto excluye la class foo::bar; de ser una statement forward válida, porque foo::bar no es un identificador. Es un nombre completamente calificado, algo diferente.

No estaría claro qué tipo de variable declarada es en realidad. La class Namespace::Class; statement directa class Namespace::Class; puede significar

 namespace Namespace { class Class; } 

o

 class Namespace { public: class Class; };