2013-07-06 13 views

Odpowiedz

21

Deklaracja użycia służy jako zwykła deklaracja: ukrywa deklaracje zakresu zewnętrznego, ale nie eliminuje wyszukiwania zależnego od argumentów (ADL).

Po dokonaniu using B::f zasadniczo nic nie zmieniasz. Po prostu redeclare B::f w zasięgu lokalnym, gdzie i tak było już widoczne. To nie przeszkadza również ADL w znalezieniu A::f, co powoduje niejasności między A::f i B::f.

Jeśli wykonasz using A::f, lokalna deklaracja A::f ukrywa zewnętrzną deklarację B::f. Tak więc B::f nie jest już widoczny i nie można go już znaleźć przez niewykwalifikowane wyszukiwanie nazwy. Teraz znajduje się tylko A::f, co oznacza, że ​​nie ma już niejasności.

Nie można wyłączyć ADL. Ponieważ argument w twoim przypadku jest typu A::X, funkcja ADL zawsze znajdzie funkcję A::f dla niekwalifikowanej nazwy f. Nie można go "wykluczyć" z rozważania. Oznacza to, że nie można wziąć pod uwagę B::f bez wywoływania niejednoznaczności. Jedynym sposobem jest użycie kwalifikowanej nazwy.

Jak słusznie zauważył @ Richich Smith w komentarzach, ADL może zostać wyłączony. ADL jest używany tylko wtedy, gdy sama nazwa funkcji jest używana jako wyrażenie Postfiks w wywołaniu funkcji. Określenie funkcji celu w jakikolwiek inny sposób przerazi ADL.

Na przykład inicjalizacji wskaźnika funkcji nie podlega ADL

void g(A::X x) 
{ 
    void (*pf)(A::X) = &f; 
    pf(x); 
} 

W powyższym przykładzie B::f zostanie wywołana. A nawet sama para () wokół nazwy funkcji jest wystarczająca, aby stłumić ADL, tj

void g(A::X x) 
{ 
    (f)(x); 
} 

wystarcza już, aby zadzwonić B::f.

+4

Można zablokować ADL na stronie wywołania, nawiasyzując nazwę funkcji. Użycie '(f) (x)' rozwiązuje niejednoznaczność. –

+0

Oczywiście "używanie B :: f;' nie jest potrzebne w żadnym z powyższych fragmentów kodu – Tony

1

Powinieneś napisać przestrzeń nazw za każdym razem jawnie. Wystarczy zrobić

#include <iostream> 

namespace A 
{ 
    class X { }; 
    void f(X) { 
     std::cout << "A"; 
    } 
} 

namespace B 
{ 
    void f(A::X) { 
     std::cout << "B"; 
    } 
    void g(A::X x) 
    { 
     // using B::f; 
     B::f(x);   
    } 
} 

int main() { 
    B::g(A::X()); // outputs B 
} 
+0

tak: ...i nigdy nie używaj "namespace xxx" - tylko zasłania i tworzy nieprzyjemne błędy (nawet "używanie przestrzeni nazw std' :) – slashmais

+0

@lashmais, oczywiście to prawda. Ale w tak małych fragmentach myślę, że jest to dozwolone. Najważniejsze, żeby się do tego nie przyzwyczaić - jeśli to zrobisz, zapomnisz nie pisać tak w prawdziwym kodzie. I tak - naprawione! –

10

Gdy kompilator próbuje rozwiązać f w f(x) stwierdzi B::f ponieważ jesteśmy w przestrzeni nazw B. Znajduje także A::f przy użyciu argument dependent lookup od x jest instancją X, która jest zdefiniowana w przestrzeni nazw A. Stąd niejednoznaczność.

Deklaracja z użyciem B::f nie ma żadnych efektów, ponieważ jesteśmy już w przestrzeni nazw B. Aby uzyskać dwuznaczność, użyj A::f(x) lub B::f(x).

Powiązane problemy