Does ADL work for the global namespace?

1k views Asked by At

Examples such as enabling outputting of std types explain how ADL can be used to "inject" a certain function/operator, depending on the type the fn/op is applied to.

I was wondering wheter ADL fully applies to the global namespace, that is, whether a type declared (or made available via using) at global namespace scope makes ADL look for matching functions in the global namespace?

Specifically, are these equivalent wrt. ADL?:

// 1 - at global namespace scope
struct GlobalType {};

template< class Ch, class Tr>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os, GlobalType const& x)
{
    os << ...;
    return os;
} 

// 2 - within namespace
namespace ecaps {

    struct EcapsType {};

    template< class Ch, class Tr>
    std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os, EcapsType const& x)
    {
        os << ...;
        return os;
    } 

}

// 3 - Type brought to global NS via using, function at global scope
namespace other {
    struct OtherType {};    
}

using other::OtherType;

template< class Ch, class Tr>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os, OtherType const& x)
{
    os << ...;
    return os;
} 

Wrt. global namespace scope not needing ADL: (update after a now deleted answer)

One Daniel Krügler of Committee fame describes an ADL problem as such:

This unqualified call has the effect that unqualified name lookup happens and as a consequence of this, the compiler searches for the name operator<<. beginning from the lexical location where the operator<< call is found "upwards" (...) starting in the current namespace and all the namespaces that include that namespace (including the global namespace, btw.) and - ...

Emph. mine. Note how the outer namespaces are described to only be considered "... from the lexical location ...". He continues:

... and - as a second route - it performs a second phase of this lookup the compiler searches in the so-called associated namespaces of the argument types occurring in this call.

In the presented example, the first phase of the search fails, because at the point where #include <iterator> exists, there is no corresponding operator<< for these argument types in any namespace. Note that your declaration of operator<< is provided lexically after the point where the call of operator<< happens somewhere in some of the library headers. The second phase of the search would also consider locations that follow the actual function call, but only within the associated namespaces.

Bold emph. mine. So it would seem to me it is relevant that ADL works for the global namespace. Of course I could easily have misunderstood something.


Note: This may be a case of the standard simply not explicitly mentioning it one way or another, because the global NS is just like any other namespace -- then again it may not, my knowledge of the Standard is very limited.

1

There are 1 answers

2
Arne Mertz On

Completely forget my initial answer, it was plain wrong.

From the C++11 standard, §3.4.2 on ADL (emphasis mine):

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.

So in short, since unqualified lookup will always search in the global namespace, ADL will never apply to global namespace.