2012-07-04 12 views
7

Sto leggendo lo standard correttamente in 5.2.8.3: ... If the type of the expression is a class type, the class shall be completely-defined. Se il tipo non è "completamente definito" vuol dire che il seguente programma non è definito?Sta usando typeid su un comportamento non definito di tipo forward dichiarato?

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 uscite: `a_ref_foo typeid nome: struct foo'

risposta

10

Quando compilo il codice con:

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

ottengo:

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’ 

che si accorda con la mia interpretazione della norma, che non è possibile applicare typeid a un tipo incompleto - e a_ref_foo è di tipo incompleto, poiché la definizione completa del tipo foo non è visibile. main.cpp (con le linee che ho aggiunto) è mal formato e una diagnostica è necessaria.

Aggiornamento:

ho riprodotto il problema con Visual Studio 2010 Express. Anche con estensioni del linguaggio disabilitate, questo programma banale:

#include <typeinfo> 

struct foo; 

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

compilato senza messaggi di diagnostica. Con gcc 4.7, ottengo:

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 stessa regola:

Se il tipo di espressione è un tipo di classe, la classe deve essere completamente definite.

appare nelle versioni 1998, 2003 e 2012 dello standard ISO C++.

Sembra un errore in Visual Studio. (Se qualcuno vuole segnalarlo a Microsoft, andare avanti.)

+4

In questo caso, l'uso di "deve" significa che è mal formato, perché questa è una regola diagnosticabile (vale a dire, non è detto che "non è richiesta alcuna diagnostica" e non è esplicitamente descritto come comportamento non definito). –

+0

@ R.MartinhoFernandes: Grazie, ho aggiornato la risposta. (Lo standard C, con il quale sono più familiare, usa "deve" diversamente: una violazione di "deve" che non è in un vincolo * esplicito * rende il comportamento del programma non definito. Le regole C++ sono trattate nella sezione 1.4, " Conformità all'implementazione ".) –

+0

La tua ipotesi su include era corretta. Mi dispiace per quello Ho anche appena provato su gcc e ho avuto gli stessi errori. Il suo interessante MSVC 10 con w4 non avvisa nemmeno. – Zac

0

Il vostro programma è completamente corretto perché funzioni get_some_foo e bar sono globali. Quindi bar è completamente definito, ma se si definisce una variante di bar in main.cpp, quindi utilizzarlo come parametro in typeid, o si verifica un errore durante la compilazione.

+0

Nell'unità di traduzione in cui è definito 'main', il tipo' foo' ** è ** incompleto. –

5

Sì, il programma è mal formato (piuttosto che causare un comportamento non definito).

Se vi chiedete perché , allora si dovrebbe considerare che typeid è un singolo operatore, ma ha completamente semantiche differenti per i tipi polimorfi che per i tipi non polimorfici.In particolare, se foo è polimorfico (ha almeno una funzione virtuale, quindi typeid produrrà un riferimento all'oggetto type_info per il tipo effettivo (in questo caso bar) mentre se il tipo non ha alcuna funzione virtuale, allora restituire un riferimento all'oggetto type_info per la statica tipo dell'espressione (in questo caso foo).

per il compilatore per generare il codice appropriato, il compilatore deve conoscere nel luogo in cui viene utilizzato typeid che dei due casi si applica.Se il tipo è incompleto, tale informazione non è presente per il compilatore.

+0

Ecco perché ha senso: questo è quello che stavo assumendo, il compilatore vede solo un tipo non polimorfico. Mi sono imbattuto in questo comportamento e stavo scavando attraverso lo standard cercando di capire cosa significasse. Grazie. – Zac

+0

@Zac: il compilatore dovrebbe aver rifiutato il tuo codice. Non è un comportamento indefinito, ma piuttosto un programma mal formato che è banalmente diagnosticabile dal compilatore. –

+0

Questa distinzione (tipo dinamico vs. statico) non si applica agli usi di typeid dove l'argomento è un nome di tipo, che GCC almeno segnala anche come errore, ad es. Struct Foo; const std :: type_info & fooType = typeid (Foo); –

Problemi correlati