Argument-dependent name lookup

Last updated

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]

Contents

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:

namespaceNS{classA{};voidf(A&a,inti){}}// namespace NSintmain(){NS::Aa;f(a,0);// Calls NS::f.}

Even though the main function is not in namespace NS, nor is namespace NS in scope, the function NS::f(A&, int) is found because of the declared types of the actual parameters 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:

#include<iostream>#include<string>intmain(){std::stringstr="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.

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

#include<iostream>intmain(){std::cout<<5;}

It works because the output operator for integers is a member function of the std::ostream class, which is the type of cout. Thus, the compiler interprets this statement as

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

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

/* 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")

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

/*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;

As Koenig points out in a personal note, [2] without ADL the compiler would indicate an error stating it could not find operator<< as the statement doesn't explicitly specify that it is found in the std namespace.

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 swap in one's own namespace and it will be used within the standard library algorithms. In other words, the behavior of

namespaceN{structA{};}// namespace NAa;Ab;std::swap(a,b);

may or may not be the same as the behavior of

usingstd::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.

Related Research Articles

Templates are a feature of the C++ programming language that allows functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one.

In computer programming, a default argument is an argument to a function that a programmer is not required to specify. In most programming languages, functions may take one or more arguments. Usually, each argument must be specified in full. Later languages allow the programmer to specify default arguments that always have a value, even if one is not specified when calling the function.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. Function objects are often called functors.

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer that points to a function. As opposed to referencing a data value, a function pointer points to executable code within memory. Dereferencing the function pointer yields the referenced function, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invoked indirectly through a variable instead of directly through a fixed identifier or address.

Foreach loop Control flow statement

Foreach loop is a control flow statement for traversing items in a collection. Foreach is usually used in place of a standard for loop statement. Unlike other for loop constructs, however, foreach loops usually maintain no explicit counter: they essentially say "do this to everything in this set", rather than "do this x times". This avoids potential off-by-one errors and makes code simpler to read. In object-oriented languages an iterator, even if implicit, is often used as the means of traversal.

In compiler construction, name mangling is a technique used to solve various problems caused by the need to resolve unique names for programming entities in many modern programming languages.

Partial template specialization is a particular form of class template specialization. Usually used in reference to the C++ programming language, it allows the programmer to specialize only some arguments of a class template, as opposed to explicit full specialization, where all the template arguments are provided.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

The Spirit Parser Framework is an object oriented recursive descent parser generator framework implemented using template metaprogramming techniques. Expression templates allow users to approximate the syntax of extended Backus–Naur form (EBNF) completely in C++. Parser objects are composed through operator overloading and the result is a backtracking LL(∞) parser that is capable of parsing rather ambiguous grammars.

C++/CLI is variant of the C++ programming language, modified for Common Language Infrastructure. It has been part of Visual Studio 2005 and later, and provides interoperability with other .NET languages such as C#. Microsoft created C++/CLI to supersede Managed Extensions for C++. In December 2005, Ecma International published C++/CLI specifications as the ECMA-372 standard.

String functions are used in computer programming languages to manipulate a string or query information about a string.

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class is private. The private members are not accessible outside the class; they can be accessed only through methods of the class. The public members form an interface to the class and are accessible outside the class.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

The C++ programming language has support for string handling, mostly implemented in its standard library. The language standard specifies several string types, some inherited from C, some designed to make use of the language's features, such as classes and RAII. The most-used of these is std::string.

In the C++ programming language, the assignment operator, =, is the operator used for assignment. Like most other operators in C++, it can be overloaded.

Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

In computer programming, variadic templates are templates that take a variable number of arguments.

In computing, associative containers refer to a group of class templates in the standard library of the C++ programming language that implement ordered associative arrays. Being templates, they can be used to store arbitrary elements, such as integers or custom classes. The following containers are defined in the current revision of the C++ standard: set, map, multiset, multimap. Each of these containers differ only on constraints placed on their elements.

In the C++ programming language, input/output library refers to a family of class templates and supporting functions in the C++ Standard Library that implement stream-based input/output capabilities. It is an object-oriented alternative to C's FILE-based streams from the C standard library.

C++14 is a version of the ISO/IEC 14882 standard for the C++ programming language. It is intended to be a small extension over C++11, featuring mainly bug fixes and small improvements, and was replaced by C++17. Its approval was announced on August 18, 2014. C++14 was published as ISO/IEC 14882:2014 in December 2014.

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. Archived from the original (PDF) on 14 December 2005. Retrieved 13 March 2012.
  2. 1 2 "A Personal Note About Argument-Dependent Lookup". 3 May 2012. Archived from the original on 17 March 2018. Retrieved 7 February 2014.