2013-07-06 37 views

Trả lời

21

Một sử dụng-khai hoạt động như một tuyên bố bình thường: nó che giấu tờ khai phạm vi bên ngoài, nhưng nó không ngăn chặn tra cứu luận phụ thuộc (ADL).

Khi bạn thực hiện using B::f, về cơ bản bạn không thay đổi gì cả. Bạn chỉ cần redeclare B::f trong phạm vi địa phương, nơi nó đã được nhìn thấy anyway. Điều đó cũng không ngăn ADL tìm được số A::f, điều này tạo ra sự mơ hồ giữa A::fB::f.

Nếu bạn làm using A::f, khai báo địa phương là A::f sẽ ẩn khai báo ngoài của B::f. Vì vậy, B::f không còn hiển thị và không còn tìm thấy bằng tra cứu tên không đủ tiêu chuẩn. Chỉ có A::f được tìm thấy ngay bây giờ, có nghĩa là không còn mơ hồ nữa.

Không thể chặn ADL. Vì đối số trong trường hợp của bạn là loại A::X, chức năng A::f sẽ luôn được ADL tìm thấy cho tên không đủ tiêu chuẩn f. Bạn không thể "loại trừ" nó khỏi xem xét. Điều đó có nghĩa là bạn không thể mang lại B::f vào xem xét mà không tạo ra sự mơ hồ. Cách duy nhất xung quanh là sử dụng tên đủ điều kiện.

Khi @Richard Smith ghi chú chính xác trong các nhận xét, ADL có thể bị chặn. ADL chỉ được sử dụng khi tên hàm chính nó được sử dụng như biểu thức postfix trong lời gọi hàm. Chỉ định hàm mục tiêu theo bất kỳ cách nào khác sẽ kích hoạt ADL.

Ví dụ, khởi tạo của con trỏ hàm là không phụ thuộc vào ADL

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

Trong ví dụ trên B::f sẽ được gọi. Và thậm chí là một cặp chỉ của () xung quanh tên hàm là đủ để ngăn chặn ADL, ví dụ:

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

là đã đủ để làm cho nó gọi B::f.

+4

Bạn có thể chặn ADL tại trang cuộc gọi bằng cách ngoặc đơn tên hàm. Sử dụng '(f) (x)' sửa chữa sự mơ hồ. –

+0

Rõ ràng 'sử dụng B :: f;' là không cần thiết trong bất kỳ đoạn mã ở trên – Tony

1

Bạn nên viết không gian tên mỗi lần một cách rõ ràng. Chỉ cần làm

#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

có: ...và không bao giờ làm 'sử dụng không gian tên xxx' - nó chỉ che khuất và làm cho các lỗi khó chịu (thậm chí không phải' sử dụng không gian tên std' :) – slashmais

+0

@slashmais, tất nhiên đó là sự thật. Nhưng trong một đoạn nhỏ như vậy tôi nghĩ rằng nó được cho phép. Điều quan trọng nhất là không quen với nó - nếu bạn làm bạn sẽ quên không viết như thế này trong mã thực. Và có - cố định! –

10

Khi trình biên dịch cố gắng giải quyết f trong f(x) nó tìm thấy B::f kể từ khi chúng tôi đang trong namespace B. Nó cũng tìm thấy A::f sử dụng argument dependent lookup kể từ x là một phiên bản của X được xác định trong không gian tên A. Do đó sự mơ hồ.

Tuyên bố sử dụng B::f không có tác dụng vì chúng tôi đã có trong không gian tên B.

Để giải quyết sự mơ hồ, hãy sử dụng A::f(x) hoặc B::f(x).

Các vấn đề liên quan