c++argument-dependent-lookupname-lookupc++-faq

What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")?


What are some good explanations on what argument dependent lookup is? Many people also call it Koenig Lookup as well.

Preferably I'd like to know:


Solution

  • Argument Dependent Lookup (ADL), sometimes called Koenig Lookup, describes how unqualified names are looked up by the compiler in C++.

    The C++11 standard § 3.4.2/1 states:

    When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function declarations (11.3) not otherwise visible may be found. These modifications to the search depend on the types of the arguments (and for template template arguments, the namespace of the template argument).

    In simpler terms Nicolai Josuttis states1:

    You don’t have to qualify the namespace for functions if one or more argument types are defined in the namespace of the function.

    A simple code example:

    namespace MyNamespace
    {
        class MyClass {};
        void doSomething(MyClass) {}
    }
    
    MyNamespace::MyClass obj; // global object
    
    
    int main()
    {
        doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
    }
    

    In the above example there is neither a using-declaration nor a using-directive but still the compiler correctly identifies the unqualified name doSomething() as the function declared in namespace MyNamespace by applying ADL.

    How does it work?

    The algorithm tells the compiler to not just look at local scope, but also the namespaces that contain the argument's type. Thus, in the above code, the compiler finds that the object obj, which is the argument of the function doSomething(), belongs to the namespace MyNamespace. So, it looks at that namespace to locate the declaration of doSomething().

    What is the advantage of ADL?

    As the simple code example above demonstrates, ADL provides convenience and ease of usage to the programmer. Without ADL there would be an overhead on the programmer, to repeatedly specify the fully qualified names, or instead, use numerous using-declarations.

    Why the criticism of ADL?

    Over-reliance on ADL can lead to semantic problems, and catch the programmer off guard sometimes.

    Consider the example of std::swap, which is a standard library algorithm to swap two values. With the ADL one would have to be cautious while using this algorithm because:

    std::swap(obj1,obj2);
    

    may not show the same behavior as:

    using std::swap;
    swap(obj1, obj2);
    

    With ADL, which version of swap function gets called would depend on the namespace of the arguments passed to it.

    If there exists a namespace A, and if A::obj1, A::obj2, and A::swap() exist, then the second example will result in a call to A::swap(), which might not be what the user wanted.

    Further, if for some reason both A::swap(A::MyClass&, A::MyClass&) and std::swap(A::MyClass&, A::MyClass&) are defined, then the first example will call std::swap(A::MyClass&, A::MyClass&) but the second will not compile because swap(obj1, obj2) would be ambiguous.

    Trivia:

    Why is it sometimes called a “Koenig lookup”?

    Because it was devised by former AT&T and Bell Labs researcher and programmer, Andrew Koenig, although Koenig himself disputes this in a 2012 blog post:

    The reason that my name is associated with argument-dependent lookup is that although I did not invent the idea, I did recognize that the introduction of namespaces causes a severe problem that ADL, or something similar, was needed to solve.

    Further reading:


    **1** The definition of ADL is as defined in Josuttis' book, *The C++ Standard Library: A Tutorial and Reference*.