Argument-dependent lookup

Argument-dependent lookup (ADL), also known as Koenig lookup[1], is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.

# Notes

Because of argument-dependent lookup, non-member functions and non-member operators defined in the same namespace as a class are considered part of the public interface of that class (if they are found through ADL) [2].

ADL is the reason behind the established idiom for swapping two objects in generic code:using std::swap; swap(obj1, obj2); because calling std::swap(obj1, obj2) directly would not consider the user-defined swap() functions that could be defined in the same namespace as the types of obj1 or obj2, and just calling the unqualified swap(obj1, obj2) would call nothing if no user-defined overload was provided. In particular, std::iter_swap and all other standard library algorithms use this approach when dealing with Swappable types.

Name lookup rules make it impractical to declare operators in global or user-defined namespace that operate on types from the std namespace, e.g. a custom operator» or operator+ for std::vector or for std::pair (unless the element types of the vector/pair are user-defined types, which would add their namespace to ADL). Such operators would not be looked up from template instantiations, such as the standard library algorithms. See dependent names for further details.

ADL can find a friend function (typically, an overloaded operator) that is defined entirely within a class or class template, even if it was never declared at namespace level.

Although a function call can be resolved through ADL even if ordinary lookup finds nothing, a function call to a function template with explicitly-specified template arguments requires that there is a declaration of the template found by ordinary lookup (otherwise, it is a syntax error to encounter an unknown name followed by a less-than character).

In the following contexts ADL-only lookup (that is, lookup in associated namespaces only) takes place:

# Defect reports

DRApplied toBehavior as publishedCorrect behavior
CWG 33C++98the associated namespaces or classes are unspecifiedif an argument used for lookup is the address of agroup of overloaded functions or a function templatespecified
CWG 90C++98the associated classes of a nested non-union classdid not include its enclosing class, but a nestedunion was associated with its enclosing classnon-unions also associated
CWG 239C++98a block-scope function declaration found in the ordinaryunqualified lookup did not prevent ADL from happeningADL not considered exceptfor using declarations
CWG 997C++98dependent parameter types and return types wereexcluded from consideration in determining the associatedclasses and namespaces of a function templateincluded
CWG 1690C++98C++11ADL could not find lambdas (C++11) or objectsof local class types (C++98) that are returnedthey can be found
CWG 1691C++11ADL had surprising behaviors for opaque enumeration declarationsfixed
CWG 1692C++98doubly-nested classes did not have associated namespaces(their enclosing classes are not members of any namespace)associated namespaces areextended to the innermostenclosing namespaces
CWG 2857C++98the associated classes of an incompleteclass type included its base classesnot included

# See also