26

Possible Duplicate:
What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")?
Why does C++ parameter scope affect function lookup within a namespace?

Today I experienced this weird behavior. I can call strangeFn without using namespace Strange first, but does not allow calling strangeFn2 Why?

namespace Strange
{
    struct X
    {
    };
    void strangeFn(X&) {}
    void strangeFn2(int) {}
}

int main()
{
    Strange::X x;
    strangeFn(x);    // GCC allows calling this function.
    strangeFn2(0);   // Error: strangeFn2 is not declared in this scope.
    return 0;
}

How does C++ compilers resolve the scope of the symbols?

L. F.
  • 19,445
  • 8
  • 48
  • 82
Calmarius
  • 18,570
  • 18
  • 110
  • 157

1 Answers1

43

This is called Argument Dependent Lookup (or Koenig Lookup)

Basically, if a symbol couldn't be resolved, the compiler will look into the namespace(s) of the argument(s).

The second function call fails, because strangeFn2 isn't visible in the current namespace, neither is it defined in the namespace of it's parameter type (int)

You can see how this works well with operator functions:

 std::complex<double> c, d;
 c += d; // wouldn't really work without ADL

or the ubiquitous iostream operators:

 std::string s("hello world");
 std::cout << s << std::endl; // Hello world would not compile without ADL...

For fun, this is what hello world would look like without ADL (and without using keyword...):

 std::string s("hello world");
 std::operator<<(std::cout, s).operator<<(std::endl); // ugly!

There are shadowy corner cases with ADL and overload resolution in the presence of function templates, but I'll leave them outside the scope of the answer for now.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 3
    Cool, didn't know this affected things as simple as "Hello World"... – rubenvb Nov 01 '11 at 10:45
  • 12
    Wow! One can never know C++ enough. – Calmarius Nov 01 '11 at 10:49
  • AFAIR namespaces of the arguments are always added to the search scope, not only if the name resolution fails (you can make an ambiguous call this way). – konrad.kruczynski Feb 21 '12 at 22:16
  • 1
    The code is buggy: `std::operator<<(std::operator<<(std::cout, s), std::endl);` should be `std::operator<<(std::cout, s).operator<<(std::endl);`, see http://ideone.com/FFKA7b – WorldSEnder Jul 06 '15 at 20:02
  • @WorldSEnder It doesn't compile because **(a)** we didn't specify the necessary casts to disambiguate the template argument for `std::endl` **(b)** I accidentally used the free-function form for `operator<<` there. Avoiding to `.operator<<` was part of the point, but I realize that actually spelling out the pointer-to-member-function type there (including the parameter type for the manipulator) would not exactly make things clearer. So let me update the code with your compromise :) – sehe Jul 06 '15 at 21:34