2011-12-01 12 views
7

Ho provato questo codice fittizio qui sotto per testare lo spazio dei nomi senza nome.spazi dei nomi con spazio dei nomi senza nome con la stessa variabile dichiarato

Ho la seguente uscita

ctor 1 
ctor 0 
3 
5 

Sono un po 'confuso su questo.

  1. mi aspettavo un errore del compilatore dicendo che non può risolvere un'ambiguità per quanto riguarda a::m_a. Invece si riferisce sempre allo meno nidificato. È sempre il caso? Quali sono le regole che C++ sta seguendo?
  2. Sembra che il compilatore crei la variabile CMyObj seguendo l'ordine scritto sul file. È sempre così?
  3. c'è un modo per accedere alla variabile m_a più nidificata da main()?.
class CMyObj{  
    public: 
    CMyObj(int a){std::cout << "ctor " << a << std::endl; } 
}; 
namespace a{ 
     namespace{ 
      int m_a=4; 
      int m_b=5; 
      CMyObj m_obj(1); 
     } 
} 
namespace a{ 
     int m_a=3; 
     CMyObj m_obj(0); 
} 
int main(){ 
     std::cout << a::m_a << std::endl; // which one? 
     std::cout << a::m_b << std::endl; // how this is possible? 
     return 0; 
} 

risposta

3

Non ho C++ 03 standard con me per controllare la dicitura lì, quindi citerò dal FDIS n3290. Penso che la risposta a questa domanda si trova nelle regole nome di ricerca qualificati in 3.4.3.2/2:

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S0(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S0(X,m) is not empty, S(X,m) is S0(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

Ora, ricordate che namespace senza nome è uno spazio dei nomi nome univoco con una direttiva using.

+0

Quest'ultima frase è la chiave. Grazie. –

+0

Ciao Gene! Grazie mille per il tuo replay (arrivando con un po 'di ritardo)! –

1

devo prendere tempo per trovare le definizioni esatte nelle specifiche, ma quando si ha un namespace anonimo (senza nome), il compilatore in realtà genera un nome storpiato. Quando si scrive

a::m_b 

nel secondo std::cout dichiarazione, il compilatore sta sostituendo automaticamente il nome storpiato in modo da potervi accedere. Incorporando dalla risposta successiva di Gene Bushuyev:

Now, remember that unnamed namespace is a uniquely named namespace with a using directive.

Nel caso dei nomi in collisione, il compilatore sa quali a::m_a mezzi, in modo che utilizza questo. È quello al livello più alto del namespace. Non penso che ci sia un modo per arrivare alla copia dello spazio dei nomi senza nome di m_a a questo punto.

Questa pagina fa un buon lavoro di spiegazione degli spazi dei nomi. Winterdom: On C++ Namespaces

+0

"Non penso che ci sia un modo per arrivare alla copia dello spazio dei nomi senza nome di m_a a questo punto." - Sembra che tu possa aprire nuovamente lo spazio dei nomi senza nome per aggiungere una funzione/alias di accesso. – visitor

1

primo sguardo a questo codice semplificato (e la mia spiegazione semplificata, si può leggere §3.4.3.2 per i dettagli):

namespace a 
{ 
    int x; 
} 

int main() 
{ 
    int i = a::x; 
} 

considerare che cosa accade quando diciamo a::x. Prima il compilatore enumera tutte le dichiarazioni di x in a. Se trova un inequivocabile x, termina correttamente. Altrimenti ricerca in modo ricorsivo gli spazi dei nomi dichiarati da una direttiva using. Se non trova mai un risultato, il programma è mal formato.

namespace a 
{ 
    int x; 
} 

namespace b 
{ 
    using namespace a; 
} 

int main() 
{ 
    int i = b::x; 
} 

Qui, non trova x in b, quindi cerca lo spazio dei nomi a (a causa del using-directive) e lo trova.Ora dovrebbe dare un senso perché questo non è ambiguo:

namespace a 
{ 
    int x; 
} 

namespace b 
{ 
    using namespace a; 
    int x; 
} 

int main() 
{ 
    int i = b::x; 
} 

Qui trova il x in b e mai considera a. Ora basta considerare che uno spazio dei nomi senza nome è in realtà solo uno spazio dei nomi con un nome sconosciuto unico:

namespace b 
{ 
    namespace 
    { 
     int x; 
    } 

    // this is what an unnamed namespace expands to (in exposition) 
    namespace __unique__ {} 
    using namespace __unique__; 

    namespace __unique__ 
    { 
     int x; 
    } 

    int x; 
} 

int main() 
{ 
    int i = b::x; 
} 

Come prima, il x in b è trovato senza considerare lo spazio dei nomi senza nome. Il tuo codice è simile

+0

Mi piace la tua spiegazione dettagliata. –

0

Non c'è alcuna ambiguità perché l'ambito di namespace::<unnamed>::m_a è lo spazio dei nomi esterno (namespace::a). Non c'è modo di accedere a namespace::<unnamed>::m_a all'interno della funzione principale ed è per questo che non vi è alcuna ambiguità. Prova il a compilare il seguente codice e si otterrà l'errore:

namespace ns{ 
    namespace { 
    int a = 2; 
    } 
    int a = 3; 
    int c = a; 
} 

variabili globali che risiedono nella stessa unità di conversione verranno inizializzate nell'ordine in cui sono dichiarati. L'ordine di inizializzazione delle variabili globali dichiarate in diverse unità di traduzione non è definito.

Problemi correlati