Search code examples
c++stlnamespacesoperator-overloadingargument-dependent-lookup

Namespace resolution with operator== in the STL


Consider a simple type, in a namespace, with an operator==:

namespace ANamespace {
    struct Foo { int i; float f; };
}

#ifdef INSIDE

namespace ANamespace {
    bool operator==(const Foo& l, const Foo& r)
    {
        return l.i == r.i && l.f == r.f;
    }
}

#else

bool operator==(const ANamespace::Foo& l, const ANamespace::Foo& r)
{
    return l.i == r.i && l.f == r.f;
}

#endif

bool compareElements(const std::vector<ANamespace::Foo>& l, const std::vector<ANamespace::Foo>& r)
{
    return l == r;
}

If operator== is defined inside ANamespace (by defining INSIDE), the example compiles. But if operator== is defined in the global namespace (the #else case), the function compareElements() doesn't compile - both in GCC and Clang, and with both libstdc++ and libc++. All emit a template error along the lines of:

In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/vector:60:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/stl_algobase.h:820:22: error: invalid operands to binary expression ('const ANamespace::Foo' and 'const ANamespace::Foo')
            if (!(*__first1 == *__first2))
                  ~~~~~~~~~ ^  ~~~~~~~~~
...

However, directly comparing two Foos in a function, e.g.,

bool compareDirectly(const ANamespace::Foo& l, const ANamespace::Foo& r)
{
    return l == r;
}

seems to work fine regardless of where operator== is defined.

Are there rules in the standard about where the STL expects operator== to be defined?


Solution

  • !(*__first1 == *__first2) takes place in std::operator==, a function template, so it is considered a dependent unqualified function call expression, so during overload resolution only functions found within the definition context of std::operator== and those found via ADL are candidates.

    Clearly there are no operator==(const Foo&, const Foo&) declared within the context of the definition of the standard comparison operator. In an argument dependent lookup (ADL) the namespaces of each of the arguments are checked to search for a viable function for the call, so this is why defining operator== inside of ANamespace works.