As mentioned by Yakk this is simply ADL: Argument Dependent Lookup.
If you don't want to bother, just remember that you should always write a free function in the same namespace as at least one of its arguments. In your case, since it's forbidden to add functions to std
, it means adding your function into the llvm
namespace. The fact that you needed to qualify the StringRef
argument with llvm::
was a dead give away.
The rules of function resolution are fairly complex, but as a quick sketch:
- name lookup: collects a set of potential candidates
- overload resolution: picks the best candidate among the potentials
- specialization resolution: if the candidate is a function template, check for any specialization that could apply
The name lookup phase which we are concerned with here is relatively simple. In short:
- it scans the argument's namespaces, then their parents, ... until it reaches the global scope
- then proceeds by scanning the current scope, then its parent scope, ... until it reaches the global scope
Probably to allow shadowing (like for any other name lookup), the lookup stops at the first scope in which it encounters a match, and haughtily ignore any surrounding scope.
Note that using
directives (using ::operator<<;
for example) can be used to introduce a name from another scope. It is burdensome though, as it puts the onus on the client, so please don't rely on its availability as an excuse for sloppiness (which I've seen done :x).
Example of shadowing: this prints "Hello, World"
without raising an ambiguity error.
#include <iostream>
namespace hello { namespace world { struct A{}; } }
namespace hello { void print(world::A) { std::cout << "Hello\n"; } }
namespace hello { namespace world { void print(A) { std::cout << "Hello, World\n"; } } }
int main() {
hello::world::A a;
print(a);
return 0;
}
Example of interrupted search: ::hello::world
yielded a function named print
so it was picked out even though it does not match at all and ::hello::print
would have been a strictly better match.
#include <iostream>
namespace hello { namespace world { struct A {}; } }
namespace hello { void print(world::A) { } }
namespace hello { namespace world { void print() {} } };
int main() {
hello::world::A a;
print(a); // error: too many arguments to function ‘void hello::world::print()’
return 0;
}