Are there different rules regarding ADL or naming clashes with regard to overloaded operators?

165 views Asked by At

I think this example best illustrates my question:

namespace N {

    class C {
    public:
        friend bool operator==(const C& c, const C& x) {
            return true;
        }
        friend bool f(const C& c, const C& x) {
            return true;
        }
    };

    class D {
    public:
        bool operator==(const D& x) {
            bool a = C{} == C{};      // this works
            return true;
        }
        bool f(const D& x) {
            bool a = f(C{}, C{});     // this does not work
            return true;
        }
    };
}

I have always viewed overloaded operators as being just like function except for the 'calling syntax' if you will. I just noticed the above difference however in ADL or name lookup rules (I don't know which one).

Can someone explain why the bool operator==(const C& c, const C& x) is found but the bool f(const C& c, const C& x) is not?

1

There are 1 answers

0
Lightness Races in Orbit On BEST ANSWER

Your D::f is hiding C::f; if you rename the latter to C::g and adjust the call then it works fine (showing that the function can be found and accessed just fine).

Your code isn't actually directly calling the operator functions, but this is done for you by the language. Consequently you're not using the name of the operator function, so no name hiding applies.

If you write operator==(C{}, C{}) (instead of C{} == C{}), then you'll see the same behaviour as f(C{}, C{}) (demo).

So, when you say "I have always viewed overloaded operators as being just like function except for the 'calling syntax' if you will", you've already hit the nail on the head.


Here's some standardese for you:

[C++11: 13.5/4]: Operator functions are usually not called directly; instead they are invoked to evaluate the operators they implement (13.5.1 – 13.5.7). They can be explicitly called, however, using the operator-function-id as the name of the function in the function call syntax (5.2.2). [ Example:

complex z = a.operator+(b); // complex z = a+b;
void* p = operator new(sizeof(int)*n);

—end example ]

[C++11: 3.3.7/4]: [..] 4) A name declared within a member function hides a declaration of the same name whose scope extends to or past the end of the member function’s class. [..]

[C++11: 3/4]: A name is a use of an identifier (2.11), operator-function-id (13.5), literal-operator-id (13.5.8), conversion-function-id (12.3.2), or template-id (14.2) that denotes an entity or label (6.6.4, 6.1).

(The [qualified] operator-function-id here is ::N::C::operator==.)