2016-06-08 1 views
0

Je suis apparemment mal compris comment la fonction C-ish de simultanément « déclarant » et en se référant à un type en utilisant struct X fonctionne en C++. (De plus, je ne sais même pas ce que cette fonction est appelée correctement.) J'ai trois exemples ci-dessous pour montrer ce que je fais mais la question principale est: Pourquoi le type imbriqué, forward déclaré de cette manière, est-il global? au lieu de la portée de la classe?utilisation de « Foo struct » dans le champ ne décl pas avant de déclarer classe imbriquée

This travaille à transmettre déclarer une struct imbriqué:

#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() {} 

Alors maintenant, je veux sauver quelques caractères en utilisant une fonction C demi-souvenir, so see où je l'ai laissé tomber la ligne struct Impl; et pour la terrain a déclaré son type comme auto_ptr<struct Impl> au lieu de 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() {} 

ici, le compilateur se plaint que no struct named 'Impl' in 'Foo2a'. Effectivement, il est à portée mondiale, comme this compile:

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

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

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

int main() {} 

Quoi de neuf avec ça? a) Pourquoi cela fonctionne-t-il de "déclarer" le type Impl de cette façon, et b) étant donné que cela fonctionne, pourquoi Impl est-il à portée globale et non à portée de classe? Et, BTW, déclarant le champ comme auto_ptr<struct Foo2c::Impl>doesn't work either.

+0

FYI: auto_ptr est obsolète et risque d'être bientôt supprimé de la langue. Pensez à utiliser "std :: unique_ptr" ou "std :: shared_ptr" à la place. – kfsone

+0

@kfsone - merci, c'est juste un exemple, substituez 'std :: shared_ptr' ou' std :: optional' si vous le souhaitez. – davidbak

+0

La réponse courte est "parce que c'est comme ça que fonctionne C++". –

Répondre

2

La portée d'un nom d'abord déclaré comme elaborated-type-specifier dépend de la façon dont il est utilisé.

Si vous faites struct Impl;, la structure est déclarée en tant que membre de la portée de la déclaration, comme dans votre premier exemple. Mais dans tout autre contexte, il est déclaré dans le bloc ou l'espace de noms le plus proche (mais pas dans la classe), comme dans les deuxième et troisième exemples.

La solution consiste simplement à le déclarer en avant comme struct Impl; dans la classe avant toute autre utilisation. Vous pouvez simplement vous y référer en tant que Impl après cela.

Voir [basic.scope.cdecl]/7 pour les règles détaillées.

+0

Merci! Maintenant que je sais que c'est un spécificateur de type _elaborated_, j'ai trouvé une bonne description de [ce que c'est] (http://en.cppreference.com/w/cpp/language/elaborated_type_specifier) ​​(même si elle n'a pas réellement la règle de portée que vous avez décrite). – davidbak