Dlaczego B :: f nie rozwiązuje dwuznaczności, ale A :: f nie?Dlaczego B :: f nie rozwiązuje dwuznaczności, ale A :: f nie?
Odpowiedz
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
.
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
}
tak: ...i nigdy nie używaj "namespace xxx" - tylko zasłania i tworzy nieprzyjemne błędy (nawet "używanie przestrzeni nazw std' :) – slashmais
@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! –
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)
.
Można zablokować ADL na stronie wywołania, nawiasyzując nazwę funkcji. Użycie '(f) (x)' rozwiązuje niejednoznaczność. –
Oczywiście "używanie B :: f;' nie jest potrzebne w żadnym z powyższych fragmentów kodu – Tony