This seems a little backwards to me but it works:
#include <iostream>
namespace nTest
{
struct cTest {};
void fTest(cTest& x)
{
std::cout << "nTest::fTest(cTest&) called" << std::endl;
}
}
int main(void)
{
nTest::cTest x;
fTest(x); //Weird! fTest is resolved since its parameter belongs to nTest.
return 0;
}
Normally, you would need nTest:: in order to access fTest, but its parameter which belongs to nTest appears to add nTest to the list of possible scopes in which to search for fTest. It seems odd to me that the parameter scope influences the function lookup.
This compiles fine in GCC, but I'm wondering is this usage portable? What is the official definition of this scoping mechanism?
It is called Koenig aka Argument dependent lookup http://en.wikipedia.org/wiki/Argument-dependent_name_lookup
That is ADL (Argument Dependent Lookup) or Koenig Lookup (for the designer of the feature). The purpose of the feature is that in many cases the same namespace will contain types and functions that can be applied to those types, all of which conform the interface. If ADL was not in place, you would have to bring the identifiers into scope with
using
declarations or you would have to qualify the calls.This becomes a nightmare since the language allows for operator overloads. Consider the following example:
While it might seem like an awkward situation, consider that
n
might be thestd
namespace,test
might beostream
, andoperator+
could beoperator<<
:Without ADL, the calls to
operator<<
would have to be explicit, and moreover you would have to know which of them is implemented as a free function versus a method. Did you know thatstd::cout << "Hi"
is calling a free function andstd::cout << 5
is calling a member function? Not many people realize it, and seriously, almost no one cares. ADL hides that from you.It was originally designed to find overloaded operators, like the operator<< you use to send a string to std::cout. If we didn't have ADL, you would have had to write your code like this instead:
std::operator<<(std::cout, "nTest::fTest(cTest&) called")
.Not too nice!
And if it works for operators, why not work the same way for functions?