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:
a
and b
have no parent or child relationships.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.