Search code examples
c++argument-dependent-lookup

why `::a::f()` is visible as `f` inside `::b::f()` scope?


Maybe I don't know something about C++, but I found incomprehensible (and dangerous in my opinion) C++ compiler behavior.

MSVC, g++ and Clang behave the same.

Q: Why function ::a::f is visible as f inside b::f(bool)?

namespace a {

struct C {
    bool value;
    C(): value(false) {}
    C(C const &): value(false) {}
    explicit C(bool value): value(value) {}
};

inline C f(bool value) { return C(value); }

// why this function is visible as `f` inside `b::f(bool)`?
inline C f(C const &value) { return C(not value.value); }

}

namespace b {

inline bool f(::a::C const &value) { return value.value; }

inline bool f(bool value) {
#ifdef WORK_AROUND_PROBLEM
    return b::f(a::f(value));
#else
    // why `::a::f` is visible as `f` here?
    return f(a::f(value)).value;
#endif
}

}


int main(int, char **) {
    if (b::f(false) || (! b::f(true))) return 1;
    if (b::f(0)) return 2;
    if (b::f(a::C(false)) || (! b::f(a::C(true)))) return 3;
    return 0;
}

I am genuinely surprised why I have to justify this question.

This question is not same as What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")? because:

  1. questions are different;
  2. in case of comparing my question and answers to referenced question - namespaces a and b have no parent or child relationships.

Solution

  • This is due to Argument dependent lookup.

    If a function takes a parameter of a custom type, the namespace that the type is declared in is searched for viable overloads when calling a function.

    f(a::f(value))
    

    Is passing a C to f. This triggers ADL, thus additionally to doing name lookup in the surounding scopes, the compiler also searches in namespace a since C is declared there.

    This is most commonly an important feature when defining free-function operator overloads. We can put them in the same namespace as the type in question, and ADL will make sure the overload is found at name-lookup without polluting the global/outer scopes.