Tôi có hai đoạn mã cho ADL cho mục đích demo. Cả hai đoạn mã đều được biên soạn bởi VC10, gcc & các trình biên dịch com ++ C++ và kết quả là giống nhau cho cả ba.Tại sao ADL được ưu tiên hơn một hàm trong 'không gian tên std' nhưng bằng chức năng trong không gian tên do người dùng xác định?
< 1> ADL chống sử dụng chỉ thị của một người sử dụng không gian tên được xác định:
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2);
}
Compile kết quả:
error C2668: 'M::swap' : ambiguous call to overloaded function
could be 'void M::swap(N::T,N::T)'
or 'void N::swap(N::T,N::T)' [found using argument-dependent lookup]
này được dự kiến như ADL không được ưu tiên hơn kết quả tra cứu thông thường cộng với ADL không phải là công dân hạng hai, kết quả tìm kiếm ADL được kết hợp với tra cứu không bình thường (không ADL) bình thường. Đó là lý do tại sao chúng ta có sự mơ hồ.
< 2> ADL chống sử dụng chỉ thị của namespace std:
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {} //point 1
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}
Cái này biên dịch ok.
Kết quả là trình biên dịch chọn kết quả ADL (nó có tiền lệ của std :: swap), nghĩa là N::swap()
tại 'điểm 1' sẽ được gọi. Chỉ khi trong 'điểm 1' vắng mặt (giả sử nếu tôi nhận xét ra dòng đó), biên dịch sẽ sử dụng sự sụt giảm trở lại std::swap
thay thế.
Lưu ý cách này đã được sử dụng ở nhiều nơi như một cách để ghi đè lên std::swap
. Nhưng câu hỏi của tôi là, tại sao ADL được ưu tiên hơn 'không gian tên std' (case2) nhưng được coi là tương đương với hàm không gian tên do người dùng định nghĩa (case1)?
Có đoạn nào trong tiêu chuẩn C++ nói như vậy không?
============================================== =================================== Chỉnh sửa sau khi đọc các câu trả lời hữu ích, có thể hữu ích cho người khác.
Vì vậy, tôi đã tinh chỉnh đoạn mã của mình 1 & giờ sự mơ hồ đã biến mất và biên dịch một cách thích hợp, thích chức năng Nontemplate khi thực hiện quá trình phân giải quá tải!
#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}
namespace M
{
template<class T>
void swap(N::T,N::T) {}
}
int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2); //here compiler choose N::swap()
}
Tôi cũng đã tinh chỉnh đoạn trích của mình 2. Chỉ để làm cho sự mơ hồ xuất hiện chỉ để giải trí!
#include <algorithm>
namespace N
{
struct T {};
template<class _Ty> inline
void swap(_Ty& _Left, _Ty& _Right)
{
_Ty _Tmp = _Move(_Left);
_Left = _Move(_Right);
_Right = _Move(_Tmp);
}
}
namespace M
{
void swap(N::T,N::T) {}
}
int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}
gcc và comeau cả nói mơ hồ như mong đợi:
"std::swap" matches the argument list, the choices that match are:
function template "void N::swap(_Ty &, _Ty &)"
function template "void std::swap(_Tp &, _Tp &)"
BTW VC10 ngu ngốc như thường lệ chúng ta hãy một đường chuyền này ok trừ khi tôi loại bỏ các 'sử dụng std :: swap'.
Chỉ cần thêm một chút để viết: C++ quá tải có thể được khôn lanh (hơn 30 trang trong C++ chuẩn), nhưng ít appendlix B có một rất có thể đọc được 10 trang có ...
Cảm ơn tất cả các đẹp đầu vào, bây giờ nó rõ ràng.
Điểm đáng lưu ý là ADL liên quan đến * tra cứu tên * và tra cứu tên không có khái niệm "ưu tiên". –
@KerrekSB: Tôi nghĩ rằng David đang nói về sau giai đoạn tra cứu tên trong khi ở độ phân giải quá tải, đó là tất cả về việc chọn trận đấu hay nhất. – Gob00st