2011-06-15 19 views
15

C'è una differenza funzionale tra questi due usi nidificati di namespace senza nome:namespace senza nome Nesting

namespace A { namespace { 
    void foo() {/*...*/} 
}} 

e

namespace { namespace A { 
    void foo() {/*...*/} 
}}} 

Per quanto vedo io, entrambi foo s avranno un unico interno identificatore per unità di compilazione e si può accedere con A::foo - ma c'è una differenza sottile o non così sottile che non vedo?

+1

(modificato) È possibile nascondere in modo efficace il secondo 'foo' dichiarando un altro' A :: foo' a livello di file. Il primo 'foo' sarà sempre accessibile come' :: A :: foo'. A meno che non si riapri 'A' e si dichiari un altro' pippo' lì. Cioè, sì, praticamente lo stesso. –

risposta

7

Esattamente come hai digitato, non c'è differenza.

È possibile, naturalmente, aggiungere dichiarazioni nel primo livello di spazio dei nomi agli esempi di stand e quindi sarà una differenza.

namespace A { 
    int i;   // Accessed globally in this file as "A::i". 
    namespace { 
    void foo() {/*...*/} 
}} 


namespace { 
    int i;   // Accessed globally in this file simply as "i". 
    namespace A { 
    void foo() {/*...*/} 
}}} 

Si noti che, anche se il programmatore non hanno modo di distinguere, per il compilatore, gli spazi dei nomi sono distinti:

unnamed_namespaces.cpp:42:5: error: reference to ‘A’ is ambiguous 
unnamed_namespaces.cpp:19:17: error: candidates are: namespace A { } 
unnamed_namespaces.cpp:28:19: error:     namespace <unnamed>::A { } 

Utile:


EDIT:

Rispetto alla ADL (Argument-dependent ricerca del nome), ho capito che sarà alcuna differenza la precedenza nella risoluzione di sovraccarico per altri foo() come di seguito:

#include <iostream> 

void foo() { std::cout << "::foo()" << std::endl; } 

namespace A { 
    namespace { 
     void foo() { std::cout << "A::<unnamed>::foo()" << std::endl; } 

     class AClass 
     { 
     public: 
      AClass() 
      { foo(); } 
     }; 
    } 
} 


namespace { 
    namespace B { 
     void foo() { std::cout << "B::<unnamed>::foo()" << std::endl; } 

     using namespace A; 

     class BClass 
     { 
     public: 
      BClass() 
      { foo(); } 

      ~BClass() 
      { A::foo(); } 
     }; 
    } 
} 

int main() 
{ 
    A::foo(); 
    B::foo(); 
    foo(); 

    A::AClass a; 
    B::BClass b; 

    return 0; 
} 

C ompiler preferirà il più vicino foo() se non specificato esplicitamente. Quindi il chiama il costruttore B::foo() anche con uno using namespace A su di esso. Per chiamare A::foo() su BClass distruttore, la chiamata deve essere esplicitamente qualificata.

A::<unnamed>::foo() 
B::<unnamed>::foo() 
::foo() 
A::<unnamed>::foo() 
B::<unnamed>::foo() 
A::<unnamed>::foo() 

Forse diventa più chiaro se pensiamo in annidati nome namespace e come sarà risolto l'argomento-dipendente. La differenza olny sarà implicita su using su quelle senza nome, ma non cambierà la preferenza del compilatore.

+2

Penso che il tuo esempio di accesso sia al contrario. Il primo è 'A :: i' e il secondo è semplicemente' i'. –

+0

Grazie Dennis. L'ho corretto. – j4x

+0

Sebbene questa sia una risposta superba finora, mi chiedevo quali tipi di effetti possono avere gli spazi dei nomi su ADL - lo spazio dei nomi A {void bar();} 'essere in grado di trovare' foo() 'in uno qualsiasi dei esempi? – ltjax