2012-07-04 8 views
7

¿Estoy leyendo el estándar correctamente en 5.2.8.3: ... If the type of the expression is a class type, the class shall be completely-defined. Si el tipo no está "completamente definido" ¿significa eso que el siguiente programa no está definido?¿Está utilizando typeid en un comportamiento indefinido de tipo declarado hacia adelante?

foo.cpp:

struct foo 
{ 
    virtual void a(){} 
}; 

struct bar : foo 
{ 
    virtual void a(){} 
}; 

bar abar; 

foo& get_some_foo() 
{ 
    return abar; 
} 

main.cpp:

#include <iostream> 
#include <typeinfo> 

struct foo; 

foo& get_some_foo(); 

int main() 
{ 
    foo& a_ref_foo(get_some_foo()); 

    std::cout << "a_ref_foo typeid name: " << typeid(a_ref_foo).name() << std::endl; 

    return 0; 
} 

MSVC10 salidas: `a_ref_foo typeid nombre: struct foo'

Respuesta

10

Cuando puedo compilar el código con:

g++ foo.cpp main.cpp -o main 

me sale:

main.cpp: In function ‘int main()’: 
main.cpp:12:52: error: invalid use of incomplete type ‘struct foo’ 
main.cpp:4:8: error: forward declaration of ‘struct foo’ 

que esté de acuerdo con mi interpretación de la norma, que no se puede aplicar typeid a un tipo incompleto - y a_ref_foo es de un tipo incompleto, ya que la definición completa del tipo foo no está visible. main.cpp (con las líneas que agregué) está mal formado, y se requiere un diagnóstico.

Actualización:

he reproducido el problema con Visual Studio 2010 Express. Incluso con las extensiones de idioma deshabilitadas, este programa trivial:

#include <typeinfo> 

struct foo; 

int main() 
{ 
    typeid (foo); 
    return 0; 
} 

compilado sin mensajes de diagnóstico. Con gcc 4.7, me sale:

main.cpp: In function ‘int main()’: 
main.cpp:7:14: error: invalid use of incomplete type ‘struct foo’ 
main.cpp:3:8: error: forward declaration of ‘struct foo’ 

La misma regla:

Si el tipo de la expresión es un tipo de clase, la clase será completamente definidos.

aparece en las versiones de 1998, 2003 y 2012 del estándar ISO C++.

Parece un error en Visual Studio. (Si alguien desea informar esto a Microsoft, adelante)

+4

En este caso, el uso de "deberá" significa que está mal formado, porque esta es una regla diagnosticable (es decir, no se dice que "no se requiere diagnóstico" y no se describe explícitamente como un comportamiento indefinido). –

+0

@ R.MartinhoFernandes: Gracias, he actualizado la respuesta. (El estándar C, con el que estoy más familiarizado, usa "shall" de manera diferente, una violación de un "shall" que no está en una * constraint explícita * hace que el comportamiento del programa sea indefinido. Las reglas de C++ están cubiertas en la sección 1.4, " Cumplimiento de la implementación ".) –

+0

Su suposición acerca de los incluidos fue correcta. Lo siento por eso. También probé gcc y obtuve los mismos errores. Su interesante MSVC 10 con w4 ni siquiera advierte. – Zac

0

Su programa es completamente correcto porque las funciones y get_some_foobar son globales. Así que bar está completamente definido, pero si define una variante de bar en main.cpp, entonces úsela como un parámetro en typeid, o se produce un error al compilar.

+0

En la unidad de traducción donde 'se define main', el tipo' foo' ** es ** incompletos. –

5

Sí, el programa está mal formado (en lugar de causar un comportamiento indefinido).

Si usted se pregunta por qué , entonces usted debe considerar que es typeid un solo operador, pero tiene completamente diferentes semántica para tipos polimórficos que para los tipos no polimórficos.En particular, si foo es polimórfico (tiene al menos una función virtual, entonces typeid producirá una referencia al objeto type_info para la real tipo (en este caso bar), mientras que si el tipo no tiene ninguna función virtual entonces será devolver una referencia al objeto type_info para la estática tipo de la expresión (en este caso foo).

para el compilador para generar el código apropiado, el compilador debe saber en el lugar donde se utiliza typeid que de los dos casos aplica. Si el tipo es incompleto, esa información no está presente para el compilador

+0

Es por eso que tiene sentido, eso es lo que estaba asumiendo, el compilador solo ve un tipo no polimórfico. Me encontré con este comportamiento y estaba investigando el estándar tratando de descubrir qué significaba. Gracias. – Zac

+0

@Zac: el compilador debería haber rechazado su código. No es un Comportamiento Indefinido, sino un programa mal formado que el compilador puede diagnosticar trivialmente. –

+0

Esa distinción (tipo dinámico vs. estático) no se aplica a los usos de typeid donde el argumento es un nombre de tipo, que al menos también se señala como un error, por ejemplo: struct Foo; const std :: type_info & fooType = typeid (Foo); –

Cuestiones relacionadas