¿Por qué no hay un rasgo de tipo std :: is_struct?

Lo he visto para comprobar si un tipo T es una clase que puedo usar:

 bool isClass = std::is_class::value; 

Devuelve verdadero para ambas clases y estructuras. Sé que en C ++ son casi lo mismo, pero me gustaría saber por qué no hay una distinción entre ellos en el rasgo de tipo. ¿Siempre es inútil verificar esta diferencia, o hay alguna razón más que no entiendo?

Devuelve verdadero para ambas clases y estructuras. Sé que en C ++ son casi lo mismo, pero me gustaría saber por qué no hay una distinción entre ellos en el rasgo de tipo.

Desafortunadamente, esta es una idea errónea común en C ++. Algunas veces proviene de malentendidos fundamentales, pero otras veces proviene de una ambigüedad en inglés. Puede provenir de diagnósticos de comstackdor inexactos, libros mal escritos, respuestas de SO incorrectas …

Probablemente hayas leído algo como esto:

“No hay diferencia en C ++ entre una estructura y una clase, excepto la visibilidad predeterminada de los miembros y las bases”.

Este pasaje puede interpretarse en un sentido que es engañoso, porque las nociones de identidad e igualdad son difíciles de distinguir cuando se usan frases como “sin diferencia”.

De hecho, C ++ no ha tenido estructuras desde 1985. Solo tiene clases.

El tipo de tipos que declara con la class palabra clave y la palabra clave struct son clases . Período. La palabra clave struct , y las reglas de visibilidad que son las predeterminadas al definir una clase que usa esa palabra clave, se mantuvieron solo por compatibilidad con C … pero eso es una syntax. No hace que los tipos resultantes sean de otro tipo.

El rasgo de tipo no hace distinción porque literalmente no hay uno que hacer.

Es imposible distinguir una diferencia en semántica para definiciones vacías como

 class C { public: }; 

de

 struct S { }; 

o similarmente

 class C { }; 

y

 struct S { private: }; 

Además de la palabra clave struct vs class , no hay diferencia de comportamiento detectable. Ver también este Q & A.

Nota : Tal como lo señala @KyleStrand, la derivación también requiere especificadores de acceso explícitos, por lo que S : private Base {}; y C : Base {}; son equivalentes, lo mismo que S : Base {}; y C : public Base {}; , donde S es una estructura, C es una clase y Base puede ser cualquiera.

Son lo mismo. La única diferencia (visibilidad predeterminada del miembro) existe solo en el momento de la comstackción. Por lo demás, no hay ninguna diferencia entre struct y class .

ETA: Lo que probablemente quieras es std::is_pod , que te dirá si tu clase es un “tipo de datos antiguo simple”. Gran parte de la discusión y comentario sobre esta pregunta parece indicar que esto es lo que realmente quieren los que piensan que debería haber una distinción.

Otros han señalado correctamente que en C ++ las palabras clave struct y class tienen el mismo significado, excepto por la diferencia en la visibilidad del miembro.

Ya sea que usted llame a los tipos agregados definidos de esta forma “estructuras” o “clases” o “weiruewzewiruz” depende de usted. En interés de la comunicación, generalmente es aconsejable seguir las convenciones establecidas, por lo que desaconsejaría “weiruewzewiruz”.

También se recomienda utilizar las diferencias semánticas como una guía para las opciones de palabras. El uso de struct es más común para datos agregados simples que no tienen mucha lógica interna e invariantes; un uso típico sería struct point { float x; float y; }; struct point { float x; float y; }; . Tales tipos a menudo se llaman “estructuras” o “estructuras” en la literatura. No sería sorprendente que alguien que utiliza fprintf en C ++ se refiriera al primer argumento como un “puntero a una estructura FILE”. FILE es un ejemplo de lo que significa Scott Meyers en “C ++ más efectivo”, ítem 34:

Es seguro suponer que una estructura de definición que comstack en ambos lenguajes [C y C ++ -pas] está diseñada de la misma manera por ambos comstackdores.

Con respecto al lenguaje natural, la “estructura” de elección de palabra no es una coincidencia: Meyers está hablando de un agregado de datos antiguo simple que tiene una semántica idéntica en ambos idiomas, hasta el nivel de bits.

En cuanto al lenguaje de progtwigción, no importaría si la definición de C ++ del agregado de datos en cuestión utilizara la palabra clave struct o class (con un especificador de acceso público). struct es quizás la elección más natural, porque la semántica C ++ del agregado es la semántica de una estructura C. Además, el uso de struct permite que las fonts C y C ++ compartan más fácilmente una definición de tipo.

El estándar C ++ usa “struct” y “structure” tanto en lenguaje natural como de progtwigción, no solo en casos de interoperabilidad: 1.7 / 5: “Una estructura declarada como”, o 3.2 / 4 struct X; // declare X as a struct type struct X; // declare X as a struct type . Lo más interesante es el 9/8, que sienta las bases para los criterios de interoperabilidad:

8 Una estructura de disposición estándar es una clase de diseño estándar definida con la estructura de clave de clase o la clase de clave de clase. […]

Cómo cualquiera que lea esto puede afirmar que no hay estructuras en C ++ me supera. Esto claramente no es un error de edición porque los términos “struct” y “clase” se establecen explícitamente en relación entre sí.


Sin embargo, más interesantes que las elecciones de palabras y los asuntos de gusto son diferencias manifiestas y comprobables. ¿Bajo qué circunstancias es un agregado de C ++ comparable y compatible con una C struct ? Tal vez esta pregunta fue la base de su pregunta? El diseño estándar mencionado en la cita es el criterio. Se detalla en 9/7 y esencialmente prescribe que

  • solo una clase en una jerarquía de herencia puede tener definiciones de miembros de datos no estáticos (probablemente porque el estándar no desea especificar el orden de los elementos de datos definidos en diferentes niveles en dicha jerarquía);
  • no se permiten funciones virtuales ni clases base virtuales (debido a los datos de instancia adicionales necesarios para la información de tiempo de ejecución);
  • todos los miembros tienen el mismo “control de acceso” (ya sea público, protegido o privado, probablemente porque el control de acceso puede ordenar libremente).

El estándar luego dice

9 [Nota: las clases de diseño estándar son útiles para comunicarse con el código escrito en otros lenguajes de progtwigción. Su diseño se especifica en 9.2.-nota final]

Por supuesto, una definición de estructura que se comstack en C cumple estos criterios, de ahí la afirmación de Scott Meyers. FILE de stdio.h es un ejemplo prominente, no del todo trivial. Tenga en cuenta que el estándar no ofrece garantías porque el diseño del objeto depende de la implementación y puede cambiar solo con una opción de comstackción.

Si una clase tiene diseño estándar se puede probar con el tipo de std::is_standard_layout . El siguiente progtwig, que está inspirado en un ejemplo sobre cppreference , verifica los casos principales establecidos en el estándar.

 #include  #include  #include  using namespace std; struct funcOnlyT // fine { int f(); }; class podT { // "class" is ok int m1; int m2; }; struct badAccessCtrlT { // bad: public/private int m1; private: int m2; }; struct polymorphicT { // bad: polymorphic int m1; int m2; virtual void foo(); }; struct inheritOkT: podT // ok: inheritance, data only on one level { int f(); }; struct inheritPlusDataT: podT // bad: inheritance, data on 2 levels { int m3; }; template struct templT // ok with std layout types T1, T2 { T1 m1; T2 m2; }; // print type "name" and whether it's std layout template void printIsStdLayout() { printf("%-20s: %s\n", typeid(T).name(), std::is_standard_layout::value ? "is std layout" : "is NOT std layout"); } int main() { printIsStdLayout(); printIsStdLayout(); printIsStdLayout(); printIsStdLayout(); printIsStdLayout(); printIsStdLayout(); printIsStdLayout >(); printIsStdLayout(); } 

Sesión de muestra:

 $ g++ -std=c++11 -Wall -o isstdlayout isstdlayout.cpp && ./isstdlayout 9funcOnlyT : is std layout 4podT : is std layout 14badAccessCtrlT : is NOT std layout 12polymorphicT : is NOT std layout 10inheritOkT : is std layout 16inheritPlusDataT : is NOT std layout 6templTIifE : is std layout 9__sFILE64 : is std layout 

C ++ 11 §9 / 8 ([clase] / 8) :

Una estructura de disposición estándar es una clase de diseño estándar definida con la struct de clave de class o la clase de clave de class . Una unión de diseño estándar es una clase de diseño estándar definida con la union clave de clase .

C ++ 11 §9 / 10 ([clase] / 10) :

Una estructura POD es una clase no sindical que es tanto una clase trivial como una clase de diseño estándar, y no tiene miembros de datos no estáticos de tipo estructura no POD, unión no POD (o matriz de tales tipos). […]

Como una estructura POD es una clase de diseño estándar, es un subconjunto de la estructura de diseño estándar . Hasta donde yo sé, este es el significado más general de struct en el estándar de C ++. Y así, presumiblemente, lo que está buscando es un rasgo de tipo o un conjunto de rasgos de tipo que le permita identificar una estructura de diseño estándar como tal.

Y voilà, mirando la lista de rasgos de tipo hay is_class y is_standard_layout . Cuando un tipo satisface ¹both es una “estructura”. O más precisamente, es una estructura de disposición estándar , como se define en C ++ 11 §9 / 8.


Respecto a

Me gustaría saber por qué no hay una distinción entre [clase y estructura] en el rasgo de tipo

Bueno, lo hay. Ese es el rasgo is_standard_layout .


Respecto a

¿Siempre es inútil verificar esta diferencia, o hay alguna razón más que no entiendo?

No, no es inútil comprobar esta diferencia. El estándar define el diseño estándar por la razón de que es muy útil en la práctica. Como el propio estándar señala,

C ++ 11 §9 / 9 ([clase] / 9) :

[Nota: las clases de diseño estándar son útiles para comunicarse con el código escrito en otros lenguajes de progtwigción. Su diseño se especifica en 9.2.-nota final]


Notas:
¹ El rasgo is_class es verdadero para una class o struct , pero no para una union , aunque el estándar define que “una unión es una clase”. Es decir, el rasgo es más específico que la terminología general.