Tra cứu Koenig , hoặc Tra cứu phụ thuộc đối số , mô tả cách các tên không đủ tiêu chuẩn được trình biên dịch tìm kiếm trong C ++.
Tiêu chuẩn C ++ 11 § 3.4.2 / 1 nêu:
Khi biểu thức postfix trong lệnh gọi hàm (5.2.2) là id không đủ tiêu chuẩn, các không gian tên khác không được xem xét trong quá trình tra cứu không đủ tiêu chuẩn (3.4.1) có thể được tìm kiếm và trong các không gian tên đó, khai báo hàm bạn bè phạm vi không gian tên ( 11.3) không thể nhìn thấy khác có thể được tìm thấy. Những sửa đổi cho tìm kiếm này phụ thuộc vào các loại đối số (và đối với đối số mẫu khuôn mẫu, không gian tên của đối số mẫu).
Nói một cách đơn giản hơn, Nicolai Josuttis tuyên bố 1 :
Bạn không phải đủ điều kiện không gian tên cho các hàm nếu một hoặc nhiều loại đối số được xác định trong không gian tên của hàm.
Một ví dụ mã đơn giản:
namespace MyNamespace
{
class MyClass {};
void doSomething(MyClass);
}
MyNamespace::MyClass obj; // global object
int main()
{
doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}
Trong ví dụ trên có không phải là một using
-declaration hay một using
-directive nhưng vẫn trình biên dịch một cách chính xác xác định tên không đủ tiêu chuẩn doSomething()
như chức năng khai báo trong namespace MyNamespace
bằng cách áp dụng tra cứu Koenig .
Làm thế nào nó hoạt động?
Thuật toán yêu cầu trình biên dịch không chỉ nhìn vào phạm vi cục bộ mà cả các không gian tên chứa kiểu của đối số. Do đó, trong đoạn mã trên, trình biên dịch thấy rằng đối tượng obj
, là đối số của hàm doSomething()
, thuộc về không gian tên MyNamespace
. Vì vậy, nó nhìn vào không gian tên đó để xác định vị trí khai báo doSomething()
.
Lợi thế của tra cứu Koenig là gì?
Như ví dụ mã đơn giản ở trên chứng minh, tra cứu Koenig cung cấp sự tiện lợi và dễ sử dụng cho lập trình viên. Nếu không có tra cứu Koenig, sẽ có một chi phí cho lập trình viên, để liên tục chỉ định các tên đủ điều kiện, hoặc thay vào đó, sử dụng nhiều using
tuyên bố.
Tại sao những lời chỉ trích của tra cứu Koenig?
Quá phụ thuộc vào tra cứu Koenig có thể dẫn đến các vấn đề ngữ nghĩa và đôi khi khiến lập trình viên mất cảnh giác.
Xem xét ví dụ về std::swap
, đó là một thuật toán thư viện tiêu chuẩn để trao đổi hai giá trị. Với việc tra cứu Koenig, người ta sẽ phải thận trọng khi sử dụng thuật toán này bởi vì:
std::swap(obj1,obj2);
có thể không hiển thị hành vi tương tự như:
using std::swap;
swap(obj1, obj2);
Với ADL, phiên bản swap
hàm nào được gọi sẽ phụ thuộc vào không gian tên của các đối số được truyền cho nó.
Nếu tồn tại một không gian tên A
và nếu A::obj1
, A::obj2
& A::swap()
tồn tại thì ví dụ thứ hai sẽ dẫn đến một cuộc gọi đến A::swap()
, đó có thể không phải là điều người dùng muốn.
Hơn nữa, nếu vì một số lý do cả hai A::swap(A::MyClass&, A::MyClass&)
và std::swap(A::MyClass&, A::MyClass&)
được xác định, thì ví dụ đầu tiên sẽ gọi std::swap(A::MyClass&, A::MyClass&)
nhưng ví dụ thứ hai sẽ không được biên dịch vì swap(obj1, obj2)
sẽ mơ hồ.
Câu đố:
Tại sao lại gọi là Tìm kiếm Koenig?
Bởi vì nó đã được nghĩ ra bởi cựu nhà nghiên cứu và lập trình viên của AT & T và Bell Labs, Andrew Koenig .
Đọc thêm:
1 Định nghĩa về tra cứu Koenig như được định nghĩa trong cuốn sách của Josuttis, Thư viện chuẩn C ++: Hướng dẫn và tham khảo .