3

I know what ADL is and I know in C++, inner scope function hides outer scope functions. That is, names do not overload across scopes. So funtion overloading need to be done in the same scope.

So now my question is, for this common code snippet:

#include <iostream>
#include <string>
using std::cout;
using std::endl;

namespace Foo{
    class Bar{
        friend void swap(Bar& a, Bar& b);
    };
    void swap(Bar& a, Bar& b){
        cout << "I am here" << endl;
    }
}

int main(int argc, char *args[]){
    Foo::Bar a, b;
    using std::swap; //These 2 lines
    swap(a, b);      //output is "I am here", Foo::swap is called
}

Along with ADL, is:

  1. custom swap and std::swap are both visiable and considered as overloaded, and then choose the best match?

  2. custom swap is found first then name lookup stops (std::swap is hidden)?


If 1. is true, how does it work? Function overloading over 2 different scopes? This contradicts what I write at the beginning. using std::swap introduce std::swap to current scope. And custom swap is in Foo::swap.

Btw, this answer What is “Argument-Dependent Lookup” (aka ADL, or “Koenig Lookup”)? seems to indicate that they are function overloading.

Further, if for some reason both A::swap(A::MyClass&, A::MyClass&) and std::swap(A::MyClass&, A::MyClass&) are defined, then the first example will call std::swap(A::MyClass&, A::MyClass&) but the second will not compile because swap(obj1, obj2) would be ambiguous.

If it's function overloading, why does my swap(Bar& a, Bar& b) not has the ambiguity issue as he describes? Is he wrong?


if 2. is true, according to C++ Primer 5th 18.2.3:

std::cin >> s;

is equivalent to:

operator>>(std::cin, s);

In this example, when the compiler sees the “call” to operator>>, it looks for a matching function in the current scope, including the scopes enclosing the output statement. In addition, because the >> expression has parameters of class type, the compiler also looks in the namespace(s) in which the types of cin and s are defined. Thus, for this call, the compiler looks in the std namespace, which defines the istream and string types. When it searches std, the compiler finds the string output operator function.

So the name lookup order is: current scope --> enclosing scopes --> argument namespace scope.

Then why is not std::swap hiding custom swap? using std::swap introduces std::swap to the current scope, which has the higher lookup priority.


Both of my assumptions seems to be invalid in some pionts and I am getting confused. Need some help. Thanks in advance.

Rick
  • 7,007
  • 2
  • 49
  • 79
  • This should answer your questions: https://en.cppreference.com/w/cpp/language/overload_resolution – HolyBlackCat May 09 '20 at 16:18
  • @HolyBlackCat *"Before overload resolution begins, the functions selected by name lookup and **template argument** deduction are combined to form the set of candidate functions..."*. Ok it seems to have something to do with template magics. I have limited knowledge of template.. Any explanation would be much appreciated. – Rick May 09 '20 at 16:34

1 Answers1

2

1. is true. For ADL,

These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.

std::swap is found by usual unqualified name lookup, and Foo::swap is found by ADL, they're both in the overload set. Foo::swap is a non-template function which is perferred to std::swap which is a template in overload resolution.

F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and

...

4) or, if not that, F1 is a non-template function while F2 is a template specialization

And about the quote from the linked answer,

if for some reason both A::swap(A::MyClass&, A::MyClass&) and std::swap(A::MyClass&, A::MyClass&) are defined,

There's no std::swap(A::MyClass&, A::MyClass&) in fact, it's just an assumption, if there's a non-template std::swap(A::MyClass&, A::MyClass&) then the invocation would be ambiguous ...

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Wait. There is no precedence between "usual unqualified name lookup" and ADL? – Rick May 09 '20 at 16:41
  • 1
    @Rick No. Both are preformed and the results are put into the overload set, then overload resolution is performed to select the best one. – songyuanyao May 09 '20 at 16:43
  • 1
    @Rick About overload resolution? In short, if both `Foo::swap` and `std::swap` are equally viable alternatives then the non-template one wins. – songyuanyao May 09 '20 at 16:47
  • Ya, I know that non-template one wins. Sorry could you tell me a little bit more about the template one? Do I get the template specialized one, created by `std::swap`, "injected" in the global scope , during compile time? – Rick May 09 '20 at 16:52
  • "injected" in the global scope or current scope, where `using std::swap` is specified? – Rick May 09 '20 at 16:55
  • @Rick I prefer to think that the name (not `std::swap` and its instantiation themselves) is introduced into the current scope, then name lookup could find it in current scope. – songyuanyao May 09 '20 at 17:01