In the C++ programming language, argument-dependent lookup (ADL), or argument-dependent name lookup, applies to the lookup of an unqualified function name depending on the types of the arguments given to the function call. This behavior is also known as Koenig lookup, as it is often attributed to Andrew Koenig, though he is not its inventor.

During argument-dependent lookup, other namespaces not considered during normal lookup may be searched where the set of namespaces to be searched depends on the types of the function arguments. Specifically, the set of declarations discovered during the ADL process, and considered for resolution of the function name, is the union of the declarations found by normal lookup with the declarations found by looking in the set of namespaces associated with the types of the function arguments.

Example

An example of ADL looks like this:

<syntaxhighlight lang="cpp">

namespace foo {

class Bar {

// ...

};

void baz(Bar& a, int i) {

// ...

}

}

int main() {

foo::Bar a;

baz(a, 0); // Calls foo::baz.

}

</syntaxhighlight>

Even though the function is not in namespace <code>foo</code>, nor is namespace <code>foo</code> in scope, the function is found because of the declared types of the actual arguments in the function call statement.

A common pattern in the C++ Standard Library is to declare overloaded operators that will be found in this manner. For example, this simple Hello World program would not compile if it weren't for ADL:

<syntaxhighlight lang="cpp">

import std;

int main() {

std::string str = "hello world";

std::cout << str;

}

</syntaxhighlight>

Using <code><<</code> is equivalent to calling <code>operator<<</code> without the <code>std::</code> qualifier. However, in this case, the overload of operator<< that works for <code>string</code> is in the <code>std</code> namespace, so ADL is required for it to be used.

The following code would work without ADL (which is applied to it anyway):

<syntaxhighlight lang="cpp">

import std;

int main() {

std::cout << 5;

}

</syntaxhighlight>

It works because the output operator for integers is a member function of the <code>std::ostream</code> class, which is the type of <code>cout</code>.

Thus, the compiler interprets this statement as

<syntaxhighlight lang="cpp">

std::cout.operator<<(5);

</syntaxhighlight>

which it can resolve during normal lookup. However, consider that e.g. the <code>const char*</code> overloaded <code>operator<<</code> is a non-member function in the <code>std</code> namespace and, thus, requires ADL for a correct lookup:

<syntaxhighlight lang="cpp">

// will print the provided char string as expected

// using ADL derived from the argument type std::cout

operator<<(std::cout, "Hi there")

// calls a ostream member function of the operator<<

// taking a void const*, which will print the address of

// the provided char string instead of the content of the char string

std::cout.operator<<("Hi there")

</syntaxhighlight>

The <code>std</code> namespace overloaded non-member <code>operator<<</code> function to handle strings is another example:

<syntaxhighlight lang="cpp">

// equivalent to

// operator<<(std::cout, str)

// The compiler searches the std namespace using ADL

// due to the type std::string of the str parameter and std::cout

std::cout << str;

</syntaxhighlight>

As Koenig points out in a personal note,