Search code examples
c++language-lawyerargument-dependent-lookupname-lookupunqualified-name

It seems to me that there are two candidate functions for the call g(parm, 1) in the example in [basic.lookup.argdep]/3


Example in [basic.lookup.argdep]/3:

namespace NS {
    class T { };
    void f(T);
    void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
    f(parm); // OK: calls NS::f
    extern void g(NS::T, float);
    g(parm, 1); // OK: calls g(NS::T, float)
}

For the call g(parm, 1) we have in the set X the declaration void g(NS::T, float); in global scope. AFAICT, we also have in set Y the declaration void g(T, int); in namespace NS, an associate namespace of the argument parm of type NS::T. Thus, if I'm not wrong, the two declarations are candidates for overload resolution. Then, is it the case that the declaration in global scope is preferred in relation to the one in namespace NS? Why? I would very much appreciate a quote from the Standard as an answer.


Solution

  • In that section, we have:

    Let X be the lookup set produced by unqualified lookup and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains

    • a declaration of a class member, or
    • a block-scope function declaration that is not a using-declaration, or
    • a declaration that is neither a function nor a function template

    then Y is empty.

    Unqualified lookup finds the block scope function declaration - extern void g(NS::T, float). Not the declaration at global scope ::g.

    Hence, Y is empty, which makes the union of X and Y trivially just X, which just contains that one declaration, which is a viable candidate.

    If that declaration were not there, then unqualified lookup would find void g(NS::T, float) and we'd go on to perform ADL, which would find N::g(T, int), which is a better match.