2010-06-14 9 views
12

Ich habe gelesen Exceptional C++ by Herb Sutter. Item 32Außergewöhnliches C++ [Bug]?

Bei Erreichen fand ich die folgende

namespace A 
{ 
    struct X; 
    struct Y; 
    void f(int); 
    void g(X); 
} 
namespace B 
{ 
    void f(int i) 
    { 
     f(i); // which f()? 
    } 
} 

Diese f() nennt sich selbst mit unendlicher Rekursion. Der Grund dafür ist, dass das einzige sichtbare f() B :: f() selbst ist.

Es gibt eine andere Funktion mit der Signatur f (int), nämlich die in Namespace A. Wenn B "mit Namespace A geschrieben hätte;" oder "using A :: f;", dann wäre A :: f (int) als Kandidat sichtbar gewesen, wenn man nach f (int) gesucht hätte, und der f (i) -Aufruf wäre zwischen A :: f mehrdeutig gewesen (int) und B :: f (int). Da B jedoch nicht A :: f (int) in den Gültigkeitsbereich gebracht hat, kann nur B :: f (int) berücksichtigt werden, so dass der Aufruf eindeutig in B :: f (int) aufgelöst wird.

Aber wenn ich folgendes tat ..

namespace A 
{ 
    struct X; 
    struct Y; 
    void f(int); 
    void g(X); 
} 
namespace B 
{ 
    using namespace A; 
    void f(int i) 
    { 
     f(i); // No error, why? 
    } 
} 

Das heißt Herb Sutter hat es alles falsch? Wenn nicht, warum bekomme ich keinen Fehler?

+1

Nur weil etwas ist kein Fehler bei der Kompilierung, bedeutet nicht, es hat wohldefinierte Semantik. –

+1

Das Schreiben von 'using A :: f' führt jedoch zu einem Kompilierzeitfehler. –

+1

Abhängig von Ihrer Version des Buches ist es bis zu 11 Jahre alt. Änderungen in C++ 03 und bald in C++ 0x werden in den Beispielen nicht berücksichtigt. (Ich weiß es nicht, aber ich vermute, dass es funktionierte, als er es zum ersten Mal schrieb.) – Bill

Antwort

18

Es gibt einen feinen Unterschied zwischen einer using-Deklaration (using A::f) und einer using-Direktive (using namespace A).

Eine using-Deklaration führt einen Namen in den Bereich ein, in dem sie verwendet wird, so dass using A::f den Aufruf an f in der Definition von B::f(int) mehrdeutig macht.

A mit Definition macht die Mitglieder des Namensraumes sichtbar in dem Umfang, in dem sie verwendet wird, aber sie erscheinen, als ob der Name von dem nächsten gemeinsamen Rahmen des Namespace eingeführt kommt und den Namensraum, in dem die using-Direktive war benutzt. Dies bedeutet, dass using namespace A; in diesem Fall die anderen f so erscheinen lassen, als ob sie im globalen Gültigkeitsbereich deklariert wären, aber sie wird immer noch von B::f(int) versteckt.

(ISO/IEC/BS 14882:. 2003 7.3.4 [namespace.udir]/1 für die alle Standard-Junkies)