2015-09-20 18 views
14

Si consideri il codice qui sotto:Perché una dichiarazione in linea non è un tipo incompleto?

struct Foo { 
    struct Bar; 
    Foo() 
    { 
     Bar bar; // Why isn't Bar an incomplete type?! 
    } 
    struct Bar {}; // Full definition 
}; 

// struct Bar {}; // fails to compile due to incomplete type 

int main() 
{ 
    Foo foo; 
} 

Si compila bene a titolo di almeno 2 compilatori (gcc5.2, clang3.5). La mia domanda è:

  • Perché non è Bar considerato un tipo incompleto nel costruttore Foo::Foo, come ho previsionali dichiaro sopra il costruttore, ma pienamente utilizzare all'interno del costruttore?

Ogni volta che mi muovo Foo::Bar di fuori della classe, in altre parole Bar diventa una classe a sé stante, ottengo l'atteso

error: aggregate 'Foo::Bar bar' has incomplete type and cannot be defined

+2

Gli organi delle funzioni membro si comportano come se fossero definiti fuori linea (vale a dire dopo la definizione della classe). –

+0

Il motivo principale è che il compilatore può eseguire la ricerca locale di tutte le definizioni all'interno della classe, quando determina come gestire ciascun tipo. L'ambito è esaminato per intero, dal momento che è solo una piccola parte del tuo programma, e non ha bisogno di fare affidamento sull'ordine delle dichiarazioni nel codice sorgente. – tp1

risposta

8

all'interno della specifica membro della classe è considerato completo ai corpi di funzione, da il progetto di C++ sezione standard 9.2[class.mem]:

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification

che significa che non hanno nemmeno trasmettere dichiarare Bar (see it live):

struct Foo { 
    Foo() 
    { 
     Bar bar; 
    } 
    struct Bar {}; 
}; 

inoltra dichiarando potrebbe essere utile per evitare violazione della sezione 3.3.7 paragraph 2 and 3.

+0

Grazie! Per quanto riguarda la tua ultima modifica, sembra che devo inoltrare dichiarazione quando la classe interna ha un identificatore di accesso diverso. Vedi per es. [this] (http://stackoverflow.com/a/32685194/3093378), se rimuovo la dichiarazione di inoltro il codice non verrà compilato (provato con gcc e clang). – vsoftco

+0

@vsoftco right, in quel caso specifico funziona senza la dichiarazione forward poiché non è uno dei luoghi in cui la classe è considerata completa come definito dal paragrafo I sopra citato. –

+0

Grazie, cristallino! – vsoftco

Problemi correlati