Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding operator lookup; which compiler is correct?

This may be asked before but I didn't have luck finding an answer...

I have an unordered container (i.e. a hash; we'll call it QHash, because it is, though this probably happens in any similar situation) that needs a comparison operator for it's key type.

Consider the following:

// foo.h
class Bar
{
public:
    class Foo {};
};

// foo.cpp
#include <QtCore/QHash>

namespace
{
    typedef Bar::Foo Foo;
    bool operator==(Foo const& a, Foo const& b) { return &a == &b; }
}

uint qHash(Foo const& foo) { return qHash(&foo); }

int main()
{
    QHash<Foo, int> hash;
    // do stuff with hash, e.g.:
    hash.insert(Foo(), 5);
    return 0;
}

Using G++, all is well. However, clang gives an error in the bowels of qhash.h about invalid operands to binary expression where trying to use == on instances of Foo. It seems to me that clang is either not finding or rejecting the definition of operator== in the anonymous namespace, probably due to different lookup rules than G++.

I am wondering, which compiler is correct?

p.s. I'm building in C++11 mode, in case it makes a difference.

like image 871
Matthew Avatar asked Jan 10 '23 12:01

Matthew


2 Answers

Well, ADL looks into the namespaces a class is defined in. Look at [basic.lookup.argdep]/2: "For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set."

Note the last sentence.

So, for the original example, the typedef in the namespace of the operator doesn't help, gcc is wrong and clang is right.

like image 168
Ville Voutilainen Avatar answered Jan 18 '23 07:01

Ville Voutilainen


This is a known GCC bug. Essentially, the problem is that GCC does not correctly implement two-phase name lookup for operator names. Your operator== is not found by unqualified lookup (because it is declared too late) and is not found by argument-dependent name lookup (because ::(anonymous namespace) is not an associated namespace of Bar::Foo, so should not be considered inside the instantiation of qHash.

If you move the definition of qHash into the anonymous namespace, GCC will then reject the code, because its bug only applies to operator names and not to normal function names.

like image 41
Richard Smith Avatar answered Jan 18 '23 05:01

Richard Smith