2015-09-20 11 views
14

Betrachten Sie den Code unten:Warum ist eine Inline-Deklaration kein unvollständiger Typ?

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; 
} 

unter mindestens 2 Compiler kompiliert fein (gcc5.2, clang3.5). Meine Frage ist:

  • Warum ist nicht Bar ein unvollständiger Typ im Konstruktor Foo::Foo betrachtet, wie ich es über den Konstruktor voraus erklären, aber es vollständig in den Konstruktor verwenden?

Immer, wenn ich Foo::Bar außerhalb der Klasse bewegen, mit anderen Worten Bar wird ein Stand-alone-Klasse, bekomme ich die erwartete

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

+2

Mitgliederfunktionskörper verhalten sich so, als wären sie außerhalb der Linie definiert (d. H. Nach der Klassendefinition). –

+0

Der Hauptgrund ist, dass der Compiler alle Definitionen innerhalb der Klasse lokal durchsuchen kann, wenn er festlegt, wie er mit jedem Typ umgehen soll. Der Umfang wird vollständig untersucht, da es nur ein kleiner Teil Ihres Programms ist und nicht auf die Reihenfolge der Deklarationen im Quellcode angewiesen ist. – tp1

Antwort

8

innerhalb der Mitglieds Spezifikation wird die Klasse abgeschlossen betrachtet in Funktionsrümpfe aus der Entwurf C++ Standard Abschnitt 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

Welche Sie bedeutet nicht einmal weiterleiten müssen Bar (see it live) erklären:

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

Vorwärts erklärt nützlich sein könnte 3.3.7 paragraph 2 and 3 Verletzung von Abschnitt zu vermeiden.

+0

Danke! In Bezug auf deine letzte Bearbeitung scheint es, dass ich deklarieren muss, wenn die innere Klasse einen anderen Zugriffsspezifizierer hat. Siehe z.B. [this] (http://stackoverflow.com/a/32685194/3093378), wenn ich die Forward-Deklaration entferne, wird der Code nicht kompiliert (versucht mit gcc und clang). – vsoftco

+0

@vsoftco Recht, in diesem speziellen Fall funktioniert es ohne die Forward-Deklaration, da dies nicht einer der Orte ist, an denen die Klasse als abgeschlossen betrachtet wird, wie durch den obigen Absatz definiert. –

+0

Danke, kristallklar! – vsoftco