¿Por qué C ++ no permite estructuras anónimas?

92

Algunos compiladores de C ++ permiten uniones y estructuras anónimas como una extensión de C ++ estándar. Es un poco de azúcar sintáctico que ocasionalmente es muy útil.

¿Cuál es la razón fundamental que impide que esto sea parte del estándar? ¿Existe un obstáculo técnico? ¿Uno filosófico? ¿O simplemente no es suficiente para justificarlo?

Aquí hay una muestra de lo que estoy hablando:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

Mi compilador aceptará esto, pero advierte que "estructura / unión sin nombre" es una extensión no estándar de C ++ .

Adrian McCarthy
fuente
3
Claramente, existe cierta confusión sobre lo que quiere decir. ¿Podría proporcionar un ejemplo de código que solo se compila debido a una extensión del compilador?
Rob Kennedy
74
Observe que hay dos conceptos que suenan similares, pero son muy diferentes: estructuras sin nombre y estructuras anónimas . El primero es este, que C ++ admite: struct { int i; } a; a.i = 0;(el tipo no tiene nombre). El segundo es este, que C ++ no admite: struct { int i; }; i = 0;(el tipo no tiene nombre y se escapa al ámbito circundante). C ++, sin embargo, hace apoyar tanto sin nombre y anónimos sindicatos .
Johannes Schaub - litb
Esto parece la biblioteca de vectores VMMLib bastante interesante. Creo que el problema es que la unión contiene una estructura sin nombre, pero no estoy seguro.
greyfade
1
FWIW Es "anónimo", no "sin nombre", y los sindicatos reciben apoyo como dice la litb. stackoverflow.com/q/14248044/560648
Lightness Races in Orbit
1
@AdrianMcCarthy: Está bien (FSVO "está bien"; el compilador molesto es críptico), pero precisamente "sin nombre" es un concepto estándar no relacionado.
Lightness Races in Orbit

Respuestas:

50

Como otros han señalado, las uniones anónimas están permitidas en C ++ estándar, pero las estructuras anónimas no.

La razón de esto es que C admite uniones anónimas pero no estructuras anónimas *, por lo que C ++ admite la primera por compatibilidad, pero no la última porque no es necesaria para la compatibilidad.

Además, no son de mucha utilidad las estructuras anónimas en C ++. El uso demuestras, que tiene una estructura que contiene tres flotadores de los cuales se puede hacer referencia a cualquiera de .v[i], o .x, .yy .z, creo que da como resultado un comportamiento indefinido en C ++. C ++ no le permite escribir a un miembro de un sindicato, digamos .v[1], y luego leer de otro miembro, digamos .y. Aunque el código que hace esto no es infrecuente, en realidad no está bien definido.

Las facilidades de C ++ para tipos definidos por el usuario proporcionan soluciones alternativas. Por ejemplo:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11 aparentemente agrega estructuras anónimas, por lo que una revisión futura de C ++ puede agregarlas.

bames53
fuente
2
+1: Mi ejemplo se basa en un comportamiento indefinido en C ++, algo que no conocía cuando escribí la pregunta.
Adrian McCarthy
2
"C ++ no le permite escribir a un miembro de un sindicato [...] y luego leer de otro miembro", a menos que dichos miembros sean objetos de diseño estándar y compartan una secuencia inicial común de miembros propios, y usted ' reescribir / leer a sus miembros dentro de dicha secuencia inicial común. Eso está permitido (es decir, definido).
underscore_d
5
@underscore_d: Sí, si los tipos son de diseño estándar con una secuencia inicial común. Sin embargo, una estructura nunca puede alias con una matriz de esta manera, porque las reglas de "secuencia inicial común" de C ++ establecen que una secuencia inicial común solo puede estar entre estructuras . Las matrices no se mencionan, por lo que no pueden usar un alias como este.
Nicol Bolas
@NicolBolas Oh, jaja, créeme, ¡he deseado muchas veces que las matrices y otras primitivas estuvieran incluidas en esta asignación! Pero no he pensado mucho en las posibles limitaciones prácticas de eso, por lo que probablemente no sea tan simple como parece actualmente. Mi comentario fue más general, pero podría haberme arriesgado a implicar por omisión que pensé que se incluían matrices en esto, así que gracias por agregar eso.
underscore_d
"La razón de esto es que C admite uniones anónimas pero no estructuras anónimas" - No. Su nota al pie aclara que estaba hablando de C99 o antes aquí. El término "unión anónima" no aparece en ninguna parte del estándar C99. GCC afirma en un diagnóstico (con las opciones -std = c99 -pedantic) que "ISO C99 no admite estructuras / uniones sin nombre". El estándar no menciona nada sobre los miembros sin nombre que no sean campos de bits sin nombre. No estoy del todo seguro de si las declaraciones de estructura son declaraciones, pero si lo son, las uniones anónimas son una violación de restricción por 6.7p2, en el mejor de los casos indefinidas.
21

Diré que puede limpiar su vector3declaración con solo usar ununion

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

Claro, las estructuras anónimas eran una extensión de MSVC . Pero ISO C11 lo permite ahora y gcc lo permite , al igual que el compilador llvm de Apple.

¿Por qué en C11 y no en C ++ 11? No estoy seguro, pero prácticamente la mayoría de los compiladores C ++ (gcc ++, MSVC ++ y el compilador C ++ de Apple) los admiten.

bobobobo
fuente
1
+1 para obtener información actualizada. La razón por la que tenía una estructura externa era porque el "código real" también tenía métodos.
Adrian McCarthy
Lo único que no puede hacer con una unión es tener miembros de datos estáticos o usar la herencia .
bobobobo
2
Gracias. Nunca pensé que una unión pudiera usarse como una estructura o clase.
Adrian McCarthy
Sé que Sun Studio no admitía estructuras anónimas antes de C ++ 11 de forma predeterminada. Si está escribiendo código multiplataforma y los compiladores no se actualizan a C + 11, no utilice la estructura anónima.
irsis
6

No estoy seguro de lo que quieres decir. Sección 9.5 de la especificación de C ++, cláusula 2:

Una unión de la forma

union { member-specification } ;

se llama unión anónima; define un objeto sin nombre de tipo sin nombre.

También puedes hacer cosas como esta:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

No siempre es muy útil ... aunque a veces es útil en definiciones de macro desagradables.

Dan
fuente
11
-1 porque dice que define una estructura anónima. Consulte los comentarios anteriores sobre la pregunta: está definiendo una estructura sin nombre, no una anónima.
Johannes Schaub - litb
1

Los sindicatos pueden ser anónimos; ver la Norma, 9.5 párrafo 2.

¿Qué propósito considera satisfactorio una estructura o clase anónima? Antes de especular por qué algo no está en el Estándar, me gustaría tener una idea de por qué debería estarlo, y no veo un uso para una estructura anónima.

David Thornley
fuente
1

Basándome en la edición, los comentarios y este artículo de MSDN: Estructuras anónimas , me arriesgaré a adivinar: encaja mal con el concepto de encapsulación. No esperaría que un miembro de una clase se meta con el espacio de nombres de mi clase más allá de simplemente agregar un miembro. Además, los cambios en la estructura anónima pueden afectar a mi clase sin permiso.

JonM
fuente
1
Debido a la forma en que se crean estructuras / uniones anónimas (es una sintaxis especial en línea que no se puede ocultar excepto por una macro), no puede sorprenderse de que algún miembro que está utilizando sea un miembro anónimo. Así que no creo que este razonamiento tenga ningún sentido. La razón real es que las uniones anónimas se admiten en C ++, solo para compatibilidad con C. C no admite estructuras anónimas (hasta C11), por lo que C ++ tampoco.
bames53
1

Tu codigo

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

es como

union Foo {
   int;
   float v[3];
};

que seguramente no es válido (en C99 y antes).

La razón es probablemente para simplificar el análisis (en C), porque en ese caso solo necesita verificar que el cuerpo de estructura / unión solo tenga "declaraciones de declarador" como

Type field;

Dicho esto, gcc y "otros compiladores" admiten campos sin nombre como extensión.

Editar: Las estructuras anónimas ahora se admiten oficialmente en C11 (§6.7.2.1 / 13).

Kennytm
fuente
5
Desde una perspectiva de análisis, no creo que union { ... }sea ​​diferente a struct { ... }. El primero es válido, pero el segundo no.
Johannes Schaub - litb
3
Dado lo absurdamente difícil que es analizar C ++ en general, dudo que las estructuras y uniones sin nombre comprometidas estándar no permitidas solo para simplificar el análisis.
Adrian McCarthy
@Adrian: Dije C, no C ++. C ++ adopta la sintaxis de C y la extiende. Probablemente los creadores de C ++ no ven la necesidad de permitir miembros de estructura / unión sin nombre para que no se metan con esa parte de la sintaxis.
kennytm
@Adrian, Buen punto Adrian, siempre pensé que "demasiado difícil de implementar" sería una preocupación para Bjarne y su equipo
bobobobo
C y C ++ admiten uniones sin nombre, por lo que el comentario que union { ... };no es válido no es correcto.
bames53