Question

Lets take some code samples:

! 4 > 0;

From C++ standard we know, that negation will be done first, than comparison. But if we expand this example a little:

#include <iostream>

class Test
{
public:
    bool operator!() const
    {
            std::cout << "operator!" << std::endl;
            return false;
    }

    bool operator>(const int &) const
    {
            std::cout << "operator>" << std::endl;
            return false;
    }
};


int main(int argc, char * argv[])
{
    Test t;
    std::cout << "t > 0;" << std::endl;
    t > 0;
    std::cout << "! t > 0;" << std::endl;
    ! t > 0;
    std::cout << "!t.operator>(0)" << std::endl;
    ! t.operator>(0);

    return 0;
}

Output of this program will be:

t > 0;
operator>
! t > 0;
operator!
!t.operator>(0)
operator>
  1. First call (control call) is quite clear. We check if operator we want is called.
  2. Second call is proof of what I stated first. negation operator is called first, than on result (bool) operator> is called.
  3. Third call is what bothers me.

And here pops my question. Why SomeObjInstance > 0 call is different from SomeObjInstance.operator>(0). I know that it's not common to call operators in second manner (as members), but why this calls differs? I always tought that SomeObjInstance > 0 is translated under the hood to member call SomeObjInstance.operator>(0) or function call bool operator>(const Test &, int) if member operator is not present.

Where this behaviour is described in C++ standard, or maybe is this some kind of undefined behaviour?

Was it helpful?

Solution

The member access operator .* has a higher precedence than the negation operator !.

Where this behaviour is described in C++ standard, or maybe is this some kind of undefined behaviour?

This is most likely the relevant paragraph:

13.5 Overloaded operators [over.oper]

5) 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).

In your first example t > 0; it will use the according operator with the precedence for the relational comparison operators. However, in your second version t.operator>(0) you use it as a function call. Thereby the Test::operator> is used as a member function, which will result in your described behavior, as it looses its operator characteristics ("they can be explicitly called, however, using the operator-function-id as the name of the function in the function call syntax").

See also:

OTHER TIPS

Just wear your compiler hat for a moment. You need to parse and evaluate an expression according to a clear set of rules (including operator precedence). The fact that the evaluation involves calling a member function ( operator>() ) that also would have been called if the expression used an operator > - so what? Do you want to make a special case and assume that in this case the default precedence should be changed? And how far are you prepared to go with it? E.g. if this method is called indirectly, or by a function pointer? I think it would complicate compiler's logic and still allow counter-intuitive examples, similar to your original question.

. and () have higher priority than !. The operator syntax is parsed as

(!t) > 0;

while the explicit invocation is parsed as

!((t.operator>)())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top