Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ ordinary lookup vs argument dependent lookup

Considering this sample described in http://en.cppreference.com/w/cpp/language/adl:

namespace A {
      struct X;
      struct Y;
      void f(int);
      void g(X);
}

namespace B {
    void f(int i) {
        f(i);   // calls B::f (endless recursion)
    }
    void g(A::X x) {
        g(x);   // Error: ambiguous between B::g (ordinary lookup)
                //        and A::g (argument-dependent lookup)
    }
    void h(A::Y y) {
        h(y);   // calls B::h (endless recursion): ADL examines the A namespace
                // but finds no A::h, so only B::h from ordinary lookup is used
    }
}

I am wondering why the ambiguity appears since the ADL rules are not taken into account if

"the lookup set produced by usual unqualified lookup contains any of the following".

Here B::g can be found by unqualified lookup as explained in http://en.cppreference.com/w/cpp/language/unqualified_lookup thanks to the rule

For a name used in the definition of a function, either in its body or as part of default argument, where the function is a member of user-declared or global namespace, the block in which the name is used is searched before the use of the name, then the enclosing block is searched before the start of that block, etc, until reaching the block that is the function body. Then the namespace in which the function is declared is searched until the definition (not necessarily the declaration) of the function that uses the name, then the enclosing namespaces, etc.

Then my question is why are ADL rules considered in this case?

like image 203
FlashMcQueen Avatar asked Mar 08 '23 11:03

FlashMcQueen


2 Answers

The full quote is

First, the argument-dependent lookup is not considered if the lookup set produced by usual unqualified lookup contains any of the following:

  1. a declaration of a class member
  2. a declaration of a function at block scope (that's not a using-declaration)
  3. any declaration that is not a function or a function template (e.g. a function object or another variable whose name conflicts with the name of the function that's being looked up)

What this means is that ADL is ignored only when unqualified lookup produces one of the above three results. Since we are not dealing with a class member, the function is declared at namespace scope, not block scope, and we only find functions we continue on and use ADL.

like image 178
NathanOliver Avatar answered Mar 21 '23 02:03

NathanOliver


why are ADL (argument dependant lookup) rules considered in this case?

Because there may be better matches in the associated namespaces. E.g.:

void f(void*);

namespace A {
struct X;
void f(X*);
}

int main() {
    A::X* x = 0;
    f(x); // A::f is the best match.
}

This mechanism is often used for swap function:

std::swap may be specialized in namespace std for user-defined types, but such specializations are not found by ADL (the namespace std is not the associated namespace for the user-defined type). The expected way to make a user-defined type swappable is to provide a non-member function swap in the same namespace as the type: see Swappable for details.

Any lvalue or rvalue of this type can be swapped with any lvalue or rvalue of some other type, using unqualified function call swap() in the context where both std::swap and the user-defined swap()s are visible.

like image 43
Maxim Egorushkin Avatar answered Mar 21 '23 01:03

Maxim Egorushkin