usar tipos tarjeta reservadas referencia porque para palabras microcontroladores estandar ejemplos datos biblioteca c++ class definition identifier standards-compliance

c++ - tipos - Por qué clase{int i;}; no es totalmente conforme a los estándares?



tarjeta de referencia ansi c (5)

Esta es una pregunta de seguimiento.

En la pregunta anterior , @ JohannesSchaub-litb dijo que el siguiente código no es totalmente conforme a los estándares:

class { int i; }; //unnamed-class definition. § 9/1 allows this!

y luego agregó,

si bien es gramaticalmente válido, infringe la regla de que dicha clase debe declarar al menos un nombre en su alcance adjunto.

Realmente no podría entender esto. ¿De qué nombre está hablando?

¿Podría alguien profundizar más en esto (preferiblemente citando el Estándar)?


El mensaje de error de GCC lo explica muy sucintamente:

$ cat > a.cc class { int i; }; $ g++ -Wall -std=c++98 a.cc a.cc:1: error: abstract declarator ‘<anonymous class>’ used as declaration

class { int i; } class { int i; } es un declarador abstracto (Estándar, §8) pero no una declaración válida (§7). Esa es la regla a la que hace referencia @ JohannesSchaub-litb: para una declaración válida, necesita algo que declarar, por ejemplo, un nombre de clase o un nombre de variable.


El punto es que al declarar la class{ int i; }; class{ int i; }; Usted está armando un montón de símbolos ( int i , en este caso) que no podrá usar en ningún otro lugar con el código que sea.

Para que este código tenga sentido, al menos debe hacer una de las siguientes cosas:

class Myclass { int i; }; //I can furthermore instantiate variables of Myclass class { int i; } myvar; //This in fact creates a myvar object typedef class { int i; } MyType; //I can funthermore instantiate variables of MyType

Al decir solo class{ int i; }; class{ int i; }; le estás diciendo al compilador:

  • mantener un int y nombrarlo i ,
  • envuélvalo en una class que nunca llamaré y ...
  • ¡olvídalo! ( }; )

Si elimina esa declaración de su programa, nada cambiará.


Está rompiendo el [basic.scope.pdecl]/6 , que dice:

El punto de declaración de una clase declarada por primera vez en un especificador de tipo elaborado es el siguiente:
- para una declaración de la forma
class-key attribute-specifier-seqopt identifier ;

el identificador se declara como un nombre de clase en el alcance que contiene la declaración, de lo contrario
- para un especificador de tipo elaborado de la forma
class-key identifier

si el especificador de tipo elaborado se utiliza en la cláusula decl-specifier-seq o parameter-declaration-de una función definida en el ámbito de espacio de nombres, el identificador se declara como un nombre de clase en el espacio de nombres que contiene la declaración; de lo contrario, excepto como una declaración de amigo, el identificador se declara en el espacio de nombre más pequeño o alcance de bloque que contiene la declaración. [Nota: estas reglas también se aplican dentro de las plantillas. - nota final] [Nota: Otras formas de especificador de tipo elaborado no declaran un nuevo nombre y, por lo tanto, deben hacer referencia a un nombre de tipo existente. Ver 3.4.4 y 7.1.6.3. - nota final]

  1. no estás creando una variable de tipo anónimo
  2. usted no es crear un tipo

Hay otro ejemplo (en [basic.def]/2 ) del estándar que demuestra que su ejemplo no cumple con los estándares:

struct S { int a; int b; }; // defines S, S::a, and S::b struct X { // defines X int x; // defines non-static data member x static int y; // declares static data member y X(): x(0) { } // defines a constructor of X }; int X::y = 1; // defines X::y enum { up, down }; // defines up and down namespace N { int d; } // defines N and N::d namespace N1 = N; // defines N1 X anX; // defines anX

Su ejemplo no define nada (excepto una estructura anónima, a quién no se puede acceder a los campos).

Tenga en cuenta una excepción sobre la enumeración, porque este caso presenta dos valores para usar.


La cláusula 9 del estándar permite la class {public: int i;} (obsérvese la falta de un punto y coma final) porque este decl-specifier-seq para una clase sin nombre podría usarse en algún otro constructo como un typedef o una declaración de variable. El problema con la class {public: int i;}; (tenga en cuenta que el punto y coma final ahora está presente) es que esta especificación de clase ahora se convierte en una declaración. Esta es una declaración ilegal según la cláusula 7, párrafo 3 de la norma:

En tales casos, y a excepción de la declaración de un campo de bits sin nombre (9.6), decl-specifier-seq introducirá uno o más nombres en el programa, o redeclarará un nombre introducido por una declaración previa.


class { int i; }; no es una declaración válida porque es una declaración simple sin una lista init-declarator pero no introduce (ni vuelve a declarar) un nombre de clase.

ISO / IEC 14882: 2011 7 [dcl.dcl] / 3:

En una declaración simple , la lista init-declarator opcional puede omitirse solo cuando se declara una clase (cláusula 9) o enumeración (7.2), es decir, cuando decl-specifier-seq contiene un class-specifier , un elaborado tipo -specificador con una clave de clase (9.1), o un enum-specifier . En estos casos y cada vez que un especificador de clase o especificador de enumeración está presente en el especificador de declinación-seq , los identificadores en estos especificadores se encuentran entre los nombres que declara la declaración (como nombres de clase, nombres enum o enumeradores , dependiendo de la sintaxis). En tales casos, y a excepción de la declaración de un campo de bits sin nombre (9.6), decl-specifier-seq introducirá uno o más nombres en el programa, o redeclarará un nombre introducido por una declaración previa.