我有两个用于演示目的的 ADL 片段。两个片段都已由 VC10、gcc 和 comeau C++ 编译器编译,并且所有三个的结果都是相同的。
<1>针对用户定义命名空间的 using 指令的 ADL:
#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);
}
编译结果:
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]
这是预期的,因为 ADL 不优先于正常查找结果加上 ADL 不是二等公民,ADL 搜索结果与正常(非 ADL)未限定查找联合。这就是为什么我们有歧义。
<2>针对 std 命名空间的 using 指令的 ADL:
#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);
}
这个编译好了。
The result is compiler choose ADL result(it take precedent of std::swap), meaning N::swap()
at 'point 1' will be called. Only when in the absense of 'point 1'(say if I comment out that line), the compile will use the fall back std::swap
instead.
Note this way has been used in many places as a way to overwrite the std::swap
.
But my question is, why does ADL takes precedence over 'std namespace'(case2) but is considered equal to user-defined namespace function(case1)?
Is there a paragraph in C++ standard that says so ?
================================================================================= Edit after reading useful answers, might be helpful to others.
So I have tweaked my snippet 1 & now the ambiguity is gone and compile apparantly prefer Nontemplate function when doing overloading resolution !
#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()
}
I have also tweaked my snippet 2. Just to make the ambiguity appear just for fun !
#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 and comeau both say ambiguity as expected:
"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 stupid as usual let this one pass ok unless I remove the 'using std::swap'.
Just a bit more to write: C++ overloading can be tricky(30+ page in C++ standard), but at appendlix B of there is a very readable 10 page there...
Thanks for all the nice inputs, now it's clear.