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.
2) namespace-scoped friend functions (and function templates) that are declared in an associated class are visible through ADL even if they are not visible through ordinary lookup 3) all names except for the functions and function templates are ignored (no collision with variables)
Argument-dependent lookup, also known as ADL, or Koenig lookup [1], is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators.
Why it is important to write “using namespace std” in C++ program? In this article, we will discuss the use of “using namespace std” in the C++ program. As the same name can’t be given to multiple variables, functions, classes, etc. in the same scope.
Name lookup rules make it impractical to declare operators in global or user-defined namespace that operate on types from the std namespace, e.g. a custom operator>> or operator+ for std::vector or for std::pair (unless the element types of the vector/pair are user-defined types, which would add their namespace to ADL).
A function call happens in several stages†:
You're confusing part 1 with part 3. The name lookup will actually put both swap
functions in the overload set ({N::swap, std::swap}
), but part 3 will decide, which one to call in the end.
Now, since std::swap
is a template, and the standard says that non-template functions are more specialized than template functions when doing overload resolution, your <2>
calls N::swap
:
§13.3.3 [over.match.best] p1
Given these definitions, a viable function
F1
is defined to be a better function than another viable functionF2
if [...]
F1
is a non-template function andF2
is a function template specialization [...]
† I recommend the first three videos of this excellent series on the subject.
Your test does not check whether ADL takes precedence or not over usual lookup, but rather how overload resolution determines the best match. The reason that the second test case works is that std::swap
is a template, and when performing overload resolution on a perfect match (found by ADL) and a template, the non-templated function takes precedence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With