Argument-dependent name lookup

In the C++ programming language, argument-dependent lookup (ADL), or argument-dependent name lookup,[1] 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.[2]

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:

namespace NS 
{
   class A {};
   void f( A &a, int i) {}
}
int main() 
{
   NS::A a;
   f( a, 0 );    //calls NS::f
}

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:

#include <iostream>
#include <string>

int main()
{
    std::string str = "hello world";
    std::cout << str;
}

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

It's also worth noting that the following code works without ADL.

#include <iostream>

int main()
{
    std::cout << "hello world";
}

It works because "hello world" in the statement

 std::cout << "hello world" ;

is of type char* and is handled by the operator<< member of the ostream class in std namespace. The compiler interperets this statement as

std::cout.operator<< ("Hello World") ;

which works without ADL as the operator<< is a member of ostream class and cout is an object of that class. Thus it is enough for the compiler to know that the ostream class is in the std namespace which is explicit in the statement.

In the previous example in which the call to

std::cout << str;

is handled by the the non-member operator<< function declared to handle strings also found in the std namespace. Thus if it weren't for ADL the compiler would have thrown an error stating it could not find operator<< as the statement doesn't explicitly specify that it is found in the std namespace.

The above is noted in an article by Mr. Andrew Koenig.[2]

Interfaces

Functions found by ADL are considered part of a class's interface. In the C++ Standard Library, several algorithms use 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 overload of swap will be used.

Criticism

While ADL makes it practical for functions defined outside of a class to behave as if they were part of the interface of that 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 is that then one can define an own version of std::swap in one's own namespace and it will be used within the standard library 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 will 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 (i.e. L1::foo(x) as opposed to using L1::foo; foo(x);) lest ADL get in the way.

References

  1. "Working Draft, Standard for Programming Language C++" (PDF). JTC1/SC22/WG21. 19 October 2005. Chapter 3.4.2 - Argument-dependent name lookup - p. 2. Retrieved 13 March 2012.
  2. 1 2 "A Personal Note About Argument-Dependent Lookup". Retrieved 7 February 2014.

External links

This article is issued from Wikipedia - version of the 11/27/2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.