Why does ADL take precedence over a function in "std namespace" but equal to a function in a user namespace?

I have two snippets for ADL for demo purposes. Both fragments were compiled by VC10, gcc and comeau C ++ compilers, and the result is the same for all three.

<1> ADL versus using the user namespace directive:

#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); } 

Compilation 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] 

It is expected that ADL will not take precedence over a normal search result, and ADL is not a second-class citizen, the ADL search result is combined with a regular (non-ADL) unmanaged search. That is why we have ambiguity.

<2> ADL versus using the std namespace directive:

 #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 fine.

As a result, the compiler selects the ADL result (it has the precedent std :: swap), which means N::swap() at point 1. Only when in the paragraph “point 1” (say, if I comment on this line), the compiler instead this will use the std::swap rollback.

Note that this method has been used in many places as a way to overwrite std::swap . But my question is: why does ADL take precedence over "std namespace" (case2), but is considered equal to the user-defined namespace function (case1)?

Is there a paragraph in the C ++ standard that says that?

==================================================== ================================ Edit after reading useful answers may be useful to others.

So, I changed my fragment 1, and now the uncertainty has disappeared and compiled, if desired, when performing the overload, the resolution prefers the Nontemplate function!

 #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 also changed my fragment 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 come both talk about 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 is stupid, as usual, let it go fine if I don't remove 'using std :: swap'.

A little more is written: C ++ overloading can be complicated (30+ pages in the C ++ standard), but appendlix B has a very readable 10-page page ...

Thanks for all the nice entries, now I see.

+6
source share
2 answers

Your test does not check if the ADL takes precedence or not over the usual search, but rather, how the definition of overload determines the best match. The reason the second test case works is because std::swap is a template, and when overload resolution is executed in perfect match (found by ADL) and the template, a function that does not have templates takes precedence.

+9
source

The function is called in several stages :

  • name lookup -> puts candidate functions in the so-called overload set
    • this is the part where ADL happens if you have an unconditional name lookup
  • template argument output -> for each template in the overload set
  • overload resolution → choose the best match

You are misleading part 1 with part 3. Searching by name will actually add both swap functions to the overload set ( {N::swap, std::swap} ), but part 3 will decide which one to call at the end.

Now, since std::swap is a template, and the standard states that functions without templates are more specialized than template functions when performing overload resolution, your calls to <2> N::swap :

§13.3.3 [over.match.best] p1

Given these definitions, a viable function F1 is defined as a better function than another viable function F2 if [...]

  • F1 is not a template function, but F2 is a specialized function of a template [...]

† I recommend the first three videos of this excellent series on this subject.

+12
source

Source: https://habr.com/ru/post/927033/


All Articles