Search code examples
c++functionnamespacesscopeargument-dependent-lookup

Understanding the scope of operators in C++


#include <iostream>

namespace Foo
{
    class Baz { };   

    std::ostream& operator<< ( std::ostream& ostream , const Baz& baz )
    {
        return ostream << "operator<<\n";
    }
}

int main()
{
    std::cout << Foo::Baz();
}

I define an operator<< in the Foo namespace. Why it can be called from the global scope?


Solution

  • DRTL

    The compiler can find the user-defined operator<< through argument-dependent lookup.

    Explanation

    The call

     std::cout << Foo::Baz();
    

    is actually an infix shorthand for

     operator<<(std::cout, Foo::Baz());
    

    Because the function call is unqualified (i.e. without any namespace prefix or surrounding parentheses), the compiler will not only do ordinary name lookup (outwards from the local function scope), but also argument-dependent lookup (a.k.a ADL) for other overloads of function operator<< in all the associated namespaces of both arguments std::cout and class Baz. These associated namespaces are std and Foo in this case.

    Thus argument-dependent lookup will find the definitions

     std::operator<<(std::ostream&, /* all the builtin types and Standard strings and streams */)
     Foo::operator<<(std::ostream&, const& Baz)
    

    After name-lookup, argument deduction will fail for all the std::operator<< overloads. This is why overload resolution will find that the user-defined Foo::operator<< is in fact the only match. That's why it is called.