Argument dependent name lookup
From Seo Wiki - Search Engine Optimization and Programming Languages
This article does not cite any references or sources. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed. (June 2008) |
In the C++ programming language, argument dependent lookup (ADL), or argument dependent name lookup, also known as Koenig 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 named after its inventor Andrew Koenig.
In ADL, other namespaces not considered during normal lookup may be searched. The set of namespaces to be searched depends on the types of the function arguments.
The set of associated namespaces for any type T is the structural scope of T (which can be used to locate friend functions) and the namespace where T is defined, if T is a structure type, together with the namespaces associated with the structure types necessary for defining the type T, excluding the types necessary only for defining members. This set of associated namespaces is included for resolving a function call with an argument of type T.
If the normal lookup of the unqualified name finds a class member function, then ADL does not occur. Otherwise, the set of declarations found by lookup is the union of the declarations found by normal lookup with the declarations found by looking in the set of associated namespaces.
An example of ADL looks like this:
namespace NS { class A {}; void f( A *&, int ) {} } int main() { NS::A *a; f( a, 0 ); //calls NS::f }
A common pattern in the Standard Template 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:
#include<iostream> int main() { std::cout << "Hello World, where did operator<<() come from?" << std::endl; return 0; }
Using <<
is equivalent to calling operator<<
, which however lacks the std
qualifier. In this case, function std::ostream& std::operator<<(std::ostream&, const char*)
is found through ADL.
Note that std::endl
is a function but it needs full qualification, since it is used
as an argument to operator<<
(std::endl
is a function pointer, not a function call).
Interfaces
Within C++, functions found by ADL are considered part of a class's interface. Within the Standard Template Library, several algorithms make use of unqualified calls to swap
from within the std
namespace. As a result, the generic std::swap
function is used if nothing else is found, but if these algorithms are used with a third-party class, Foo
, found in another namespace that also contains swap(Foo&, Foo&)
, that specialization of swap
will be used.
Criticism
While ADL makes it practical for free functions to be part of the interface of a class, it makes namespaces less strict and so can require the use of fully-qualified names when they would not otherwise be needed. For example, the C++ standard library makes extensive use of unqualified calls to std::swap to swap two values. The idea being that then one can define an own version of std::swap in one's own namespace and it will be used within the STL algorithms. In other words, the behavior of
std::swap(a, b);
may or may not be the same as the behavior of
using std::swap; swap(a, b);
(where a
and b
are of type N::A
) because if N::swap(N::A&, N::A&)
exists, the second of the above examples call it while the first will not. Furthermore, if for some reason both N::swap(N::A&, N::A&)
and std::swap(N::A&, N::A&)
are defined, then the first example will call std::swap(N::A&, N::A&)
but the second will not compile because swap(a, b)
would be ambiguous.
In general, over-dependence on ADL can lead to semantic problems. If one library, L1
, expects unqualified calls to foo(T)
to have one meaning and another library, L2
expects it to have another, then namespaces lose their utility. If, however, L1
expects L1::foo(T)
to have one meaning and L2
does likewise, then there is no conflict, but calls to foo(T)
would have to be fully qualified (as opposed to using L1::foo; foo(x);
) lest ADL get in the way.
External links
- What's In a Class? - The Interface Principle by Herb Sutter
- Namespaces and the Interface Principle by Herb Sutter
- Why I Hate Namespaces by Danny Kalev
- "A Modest Proposal: Fixing ADL (revision 2)" by Herb Sutterde:Argument dependent name lookup
↓