I have two snippets for ADL for demo purposes. Both snippets have been compiled by VC10, gcc & comeau C++ compilers, and the result are the same for all three.
<1>ADL against using directive of a user defined namespace:
#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 result:
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]
This is expected as ADL doesn't take precedence over normal lookup result plus ADL is not 2nd class citizen, the ADL search result is unioned with normal(non ADL) unquailfied lookup. That's why we have the ambiguity.
<2>ADL against using directive of std namespace:
#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);
}
This one compiles ok.
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.