2016-06-08 16 views
0

Ich verstehe anscheinend, wie das C-ish-Feature der gleichzeitig "deklariert" und verweist auf einen Typ struct X funktioniert in C++. (Ich weiß nicht einmal, wie diese Funktion richtig heißt.) Ich habe drei Beispiele unten, um zu zeigen, was ich tue, aber die Hauptfrage lautet: Warum ist der verschachtelte Typ, der auf diese Weise vorwärts deklariert wird, global gültig? statt im Klassenraum?Verwendung von "struct Foo" im Feld decl leitet nicht weiter deklarieren geschachtelte Klasse

This arbeitet eine verschachtelte Struktur weiterleiten erklären:

#include <memory> 
class Foo1 
{ 
    Foo1(); 
    ~Foo1(); 
    struct Impl; 
    std::auto_ptr<Impl> m_pimpl; 
}; 

struct Foo1::Impl 
{ 
    Impl(){} 
    ~Impl(){} 
}; 

Foo1::Foo1(){} 
Foo1::~Foo1(){} 

int main() {} 

So nun möchte ich unter Verwendung eines Halb erinnerte C-Funktion, ein paar Zeichen speichern so see, wo ich für die abgenommene habe die Linie struct Impl; und Feld erklärte seine Art als auto_ptr<struct Impl> statt auto_ptr<Impl>:

#include <memory> 
class Foo2a 
{ 
    Foo2a(); 
    ~Foo2a(); 
    std::auto_ptr<struct Impl> m_pimpl; 
}; 

struct Foo2a::Impl 
{ 
    Impl(){} 
    ~Impl(){} 
}; 

Foo2a::Foo2a(){} 
Foo2a::~Foo2a(){} 

int main() {} 

Hier ist der Compiler, dass no struct named 'Impl' in 'Foo2a' beschwert. Sicher genug, ist es im globalen Bereich, wie this kompiliert:

#include <memory> 
class Foo2b 
{ 
    Foo2b(); 
    ~Foo2b(); 
    std::auto_ptr<struct Impl> m_pimpl; 
}; 

struct Impl 
{ 
    Impl(){} 
    ~Impl(){} 
}; 

Foo2b::Foo2b(){} 
Foo2b::~Foo2b(){} 

int main() {} 

Was ist da los? a) Warum funktioniert es überhaupt, den Typ Impl auf diese Weise zu "deklarieren", und b) vorausgesetzt, dass es funktioniert, warum ist Impl im globalen Bereich nicht Klassenbereich?

Und, BTW, das Feld als auto_ptr<struct Foo2c::Impl>doesn't work either deklarieren.

+0

FYI: auto_ptr ist veraltet und wird wahrscheinlich bald aus der Sprache entfernt. Ziehen Sie stattdessen "std :: unique_ptr" oder "std :: shared_ptr" in Betracht. – kfsone

+0

@ kfsone - Danke, es ist nur ein Beispiel, ersetze 'std :: shared_ptr' oder' std :: optional' wenn du willst. – davidbak

+0

Die kurze Antwort lautet "weil C++ so funktioniert". –

Antwort

2

Der Geltungsbereich eines Namens, der zuerst als erarbeiteter Typspezifizierer deklariert wurde, hängt von der Art und Weise ab, in der er verwendet wird.

Wenn Sie struct Impl; tun, wird die Struktur als ein Mitglied des Geltungsbereichs deklariert, in dem diese Deklaration auftritt, wie in Ihrem ersten Beispiel. Aber in jedem anderen Kontext wird es wie im zweiten und dritten Beispiel im nächsten umschließenden Block oder Namespace (aber nicht in der Klasse) deklariert.

Die Lösung ist nur, um es als struct Impl; in der Klasse vor allen anderen Verwendungen vorwärts zu deklarieren. Sie können danach nur noch Impl nennen.

Siehe [basic.scope.cdecl]/7 für die detaillierten Regeln.

+0

Danke! Nun, da ich weiß, dass es ein _Laboratored-Type-specifier_ ist, habe ich eine gute Beschreibung von [was das ist] gefunden (http://en.cppreference.com/w/cpp/language/elaborated_type_specifier) ​​(obwohl es nicht wirklich hat die von Ihnen beschriebene Bereichsregel). – davidbak