2011-02-03 17 views
22

Tôi có một đoạn mã nhỏ ở đây để xem xét của bạn mà câu đố tôi khá nhiều. Điều kỳ lạ là nó biên dịch trên cả Sun Studio và GCC mặc dù tôi nghĩ nó không nên.Các hàm có đối số lớp bị rò rỉ từ không gian tên?

Hãy xem xét điều này:

namespace name 
{ 
    class C 
    { 
     int a; 
    }; 

    void f(C c); 
    void g(int a); 
} 

int main(int argc, char** argv) 
{ 
    name::C c; 

    name::f(c); 
    f(c); // <--- this compiles, strangely enough 

    name::g(42); 
    // g(42); <--- this does not, as I expected 
} 

Đối số lớp từ không gian tên tương tự gây nên các chức năng f để 'rò rỉ' ra khỏi không gian tên và có thể truy cập mà không name::.

Có ai có lời giải thích cho điều này không? Nó chắc chắn là tôi và không phải trình biên dịch là sai ở đây.

+0

Thú vị, trình biên dịch intel BTW (icpc) cũng biên dịch ... – Artyom

+0

Đã chỉnh sửa câu hỏi của riêng tôi để xóa các bit không thích hợp và giúp tìm kiếm dễ dàng hơn cho những người khác có cùng vấn đề. – lytenyn

Trả lời

28

Nó được gọi là argument-dependent lookup (hoặc Koenig tra cứu). Tóm lại, trình biên dịch sẽ tìm kiếm hàm trong các không gian tên là các không gian tên của các kiểu đối số.

+1

Cảm ơn bạn, đây là một tính năng C++ mà tôi chưa bao giờ nghe đến .. – lytenyn

+5

@lytenyn: đó là một trong những bạn sử dụng hàng ngày mặc dù :) 'std :: string s; s + = "aa"; ', ở đây' + = 'xuất phát từ không gian tên' std' mặc dù bạn không bao giờ chỉ định nó, nhờ ADL. –

+0

@ matthieu-m: bạn hoàn toàn đúng, tất nhiên, cũng giống như khi sử dụng iostream. Nhưng đây là những điều nhỏ mà bạn không bao giờ nghĩ đến trừ khi ai đó đẩy mũi vào đó :) Ngoài ra, tôi không thể nhớ lại bất kỳ cuốn sách C++ nào mà tôi đã từng đề cập đến, mặc dù nó rất cơ bản. Điều này có thể chỉ là trí nhớ của tôi, tất nhiên. – lytenyn

11

Đây là Argument-Dependent Name Lookup, a.k.a. ADL, a.k.a. Koenig tra cứu. Điều này đã được phát minh để làm cho các nhà khai thác công việc như mong muốn, ví dụ:

namespace fu { 
    struct bar { int i; }; 
    inline std::ostream& operator<<(std::ostream& o, const bar& b) { 
     return o << "fu::bar " << b.i; 
    } 
} 

fu::bar b; 
b.i = 42; 
std::cout << b << std::endl; // works via ADL magic 

Without ADL bạn phải hoặc là mang lại một cách rõ ràng các nhà điều hành sản xuất với xấu xí using fu::operator<<;, hoặc sử dụng cuộc gọi thậm chí xấu xí rõ ràng:

fu::operator<<(std::cout, b) << std::endl; 
+1

+1 cho liên kết, chúc bạn đã tóm tắt bài viết. – Crisfole

+2

Bài viết rất ngắn, sự tò mò của bạn ở đâu? –

6

Đó là do "tra cứu phụ thuộc đối số". Việc xóa bỏ const sẽ không thay đổi hành vi bạn đang thấy. Để chứng minh rằng nó là ADL, thử di chuyển St struct bên ngoài namespace ...

struct St 
{ 
    int a; 
}; 

namespace name 
{ 
    void f(const St& st); 
    void g(int a); 
} 

int main(int argc, char** argv) 
{ 
    St st; 

    name::f(st); 
    f(st); // <--- now you will get the expected compile error 

    name::g(42); 
    // g(42); <--- this does not, as I expected 
} 
1

Đó là do luận phụ thuộc tra cứu.

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