Argument-dependent lookup (ADL) is a set of rules by which C++ identifies unqualified function calls and operator overloading function calls.

Mainly, it uses the classes or namespaces of the provided user-defined arguments to look for the unqualified identifier name in the classes or namespaces. If classes or namespaces contain the identifier, the classes or namespaces are added in the lookup. Once the lookup is ready, the better option then gets chose to use.

It is better to understand this with the help of an example:

#include <iostream>
 
int main()
{
    operator>>(std::cout, "Hello world\n");
    return 0;
}

Does this program work? If it works, why?…

This program successfully compiles and runs. How does compiler identify operator>> function? This happens because of ADL where C++ looks the class or namespace where std::cout is defined. std::cout is defined in std namespace which also contains std::operator<<. Namespace std is then added to the lookup. As there is no other operator<< function in the local or global scope, std::operator<< is chosen to be used.

Tip

So, there is already a unqualified lookup happens where it looks for the unqualified identifiers in the local and global scope. Apart from this lookup, ADL also used by C++ to identify unqualified identifiers.

Another example

We can also use a custom program to demonstrate this. Let’s create a namespace adl (just for namesake) which contains Value and a print function to print Value.

#include <iostream>
 
namespace adl
{
    struct Value
    {
        int value{10};
    } value{};
 
    void print(Value &v)
    {
        std::cout << v.value << '\n';
    }
}
 
int main(int argc, char const *argv[])
{
    print(adl::value);
    return 0;
}

As print is not defined in either local scope or global scope, C++ uses ADL to identify print by adding namespace adl in the lookup.

There are different rules provided at cppreference page. Some of the common rules are:

  1. ADL only works for calls. For example, it works for print() not print.
  2. ADL works with arguments of user-defined (or program-defined) types. So, ADL will have no effect on arguments of fundamental types.
  3. ADL includes base classes if used with argument of type derived class.

References

  1. https://en.cppreference.com/cpp/language/adl