Argument-dependent lookup
Argument-dependent lookup, also known as ADL, or Koenig lookup, 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.
Argument-dependent lookup makes it possible to use operators defined in a different namespace
#include <iostream> int main() { std::cout << "Test\n"; // There is no operator<< in global namespace, but ADL // examines std namespace because the left argument is in // std and finds std::operator<<(std::ostream&, const char*) operator<<(std::cout, "Test\n"); // same, using function call notation // however, std::cout << endl; // Error: 'endl' is not declared in this namespace. // This is not a function call to endl(), so ADL does not apply endl(std::cout); // OK: this is a function call: ADL examines std namespace // because the argument of endl is in std, and finds std::endl (endl)(std::cout); // Error: 'endl' is not declared in this namespace. // The sub-expression (endl) is not a function call expression }
Contents |
Details
First, if the lookup set produced by usual unqualified lookup contains any of the following:
Then the argument-dependent lookup is not considered.
Otherwise, for every argument in a function call expression and for every template template argument of a template function, its type is examined to determine the associated set of namespaces and classes that it will add to the lookup
If any namespace in the associated set of classes and namespaces is an inline namespace, its enclosing namespace is also added to the set.
If any namespace in the associated set of classes and namespaces directly contains an inline namespace, that inline namespace is added to the set.
After the associated set of classes and namespaces is determined, the set of declarations found by ordinary unqualified lookup and the set of declarations found in the associated set of classes and namespaces produced by ADL are merged, with the following special rules
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) [1].
ADL is the reason behind the established idiom for swapping two objects in generic code:using std::swap; swap(obj1, obj2);
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, even if it was never declared at namespace level.
Examples
This section is incomplete Reason: more examples |
Example from http://www.gotw.ca/gotw/030.htm
namespace A { struct X; struct Y; void f(int); void g(X); } namespace B { void f(int i) { f(i); // calls B::f (endless recursion) } void g(A::X x) { g(x); // Error: ambiguous between B::g (ordinary lookup) // and A::g (argument-dependent lookup) } void h(A::Y y) { h(y); // calls B::h (endless recursion): ADL examines the A namespace // but finds no A::h, so only B::h from ordinary lookup is used } }
See also
References
- ↑ H. Sutter (1998) "What's In a Class? - The Interface Principle" in C++ Report, 10(3)