Are any C++ operator overloads provided automatically based on others? [duplicate]
Asked Answered
K

4

8

Say I'm writing an int wrapper and need to provide every single operator overload. Must the author list out every single one, or can it auto-generate any based on what the author has provided? Can/does the compiler infer any new auto-defined operators from existing ones?

If I define operator==, does it give me an operator!= automatically? Or vice-versa?

If I define operator++(), do I get operator++(int) for free? Or vice versa?

How about the += type business? Can it combine existing definitions of operator+ with operator= to generate operator+=? In theory it should be possible but does it?

Same question for >= to <, etc, or do I have to fully list out definitions for >,>,>=,<=?

Keavy answered 28/9, 2015 at 6:26 Comment(4)
There's a proposal for comparison operator defaulting.Tour
It is easy enough to test this.Tynes
boost has some operators based on others: boost.org/doc/libs/1_59_0/libs/utility/operators.htmPrerecord
@user657267: Thanks, that proposal makes sense. I wish there was one for operator++() to operator++(int) as well, I feel like you should only have to give one of those.Keavy
R
4

In the core language the various operators are independent. Some are defined in terms of others, but if overload resolution for an operator invocation fails then there is no attempt to express that invocation in terms of other operators. When that's desired it can easily be expressed by the programmer (the opposite, turning off such machinery, would probably be more difficult).

There is a set of relational operator overloads in std::rel_ops that client code can use, defined in terms of < and ==.

You can easily write a mixin-class that provides relational operators in terms of < and ==, or in terms of a tri-valued compare function. That was the original motivation for the Curiously Recurring Template Pattern, called the Barton-Nackman trick.

Reamy answered 28/9, 2015 at 6:30 Comment(0)
S
3

No.

C++ has no inference rules in the core language, so even defining say + it doesn't assume anything about +=... they're just (as far as the language goes) totally unrelated.

Consider that the << (left bit-shift operator) in the standard library has been overloaded to mean "output to stream"... just because of the look and of a sensible priority and associativity.

Sphinx answered 28/9, 2015 at 6:29 Comment(4)
It looks like you're right, but things like == and != are inherently similar in 99% of applications... they could auto-generate it and require the user to delete the auto-generated one if they want to do something strange.Keavy
Note that the usual inference is from += to +, not the other way around. In particular c = a+ b is inferred as c = a; c += b;. The reason is that at CPU level, + is more complex. It takes two input registers and an output register. += only takes one input register.Forgetmenot
@MSalters: In the past I've spent some time investigating what was the best code quality when defining an n-dimensional vector class (vector in the math sense) in C++. I found that, depending on the compiler, some implementation was better defining + in terms of +=, some other the other way around and that, unfortunately, no implementation was producing code as good as hand-unrolled component-by-component math. It was a few years ago, may be now compiler are smarter and the situation is better.Sphinx
@6502: Modern C++ template code would be expanded inline and allow loop unrolling since the vector size would be a compile-time constant. That's 1990's level optimization, but it requires modern code.Forgetmenot
D
1

C++ 20 operator <=>

It appears that with C++20, std::rel_ops is deprecated, and defaulting <=> will automatically give ==, !=, <, >, <=, >= for free.

Adapted from https://en.cppreference.com/w/cpp/language/default_comparisons:

main.cpp

#include <cassert>
#include <compare>
#include <set>

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

int main() {
    Point pt1{1, 1}, pt2{1, 2};

    // Just to show it Is enough for `std::set`.
    std::set<Point> s;
    s.insert(pt1);

    // Do some checks.
    assert(!(pt1 == pt2));
    assert( (pt1 != pt2));
    assert( (pt1 <  pt2));
    assert( (pt1 <= pt2));
    assert(!(pt1 >  pt2));
    assert(!(pt1 >= pt2));
}

Compile and run:

sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

More details at: What is the <=> operator in C++?

Tested on Ubuntu 20.04, GCC 10.2.0.

Duteous answered 10/11, 2020 at 15:20 Comment(0)
I
1

C++20 adds a feature allowing the language to do something like this for relational (<, >, <=, >=) and equality operators (== and !=).

When using equality operators, the system can attempt to reverse the order of the operands (for equality testing of different types) as well as negate the result in order to find an appropriate operator== overload. That is, if you only implement operator== for equality testing A with B, this will also allow you to equality test B with A, and inequality test them as well.

Note that the compiler is not generating operator functions for you. It is instead modifying the actual place where it is invoking the operator. That is, it turns b != a into !(a == b) in order to find an appropriate == operator.

For <=>, it gets applied to all of the relational operators (but not the equality operators) in much the same way. The system will rewrite a < b to be (a <=> b) < 0 or (b <=> a) > 0 as needed to find a matching overloaded <=> operator.

Additionally, you can = default any of the comparison operators, which does a subobject-wise, in order comparison of the subobjects of the type in question (you can only default comparisons of the same type). If you default the == operator, then per the above rules, you effectively get != as well. If you default <=>, you get all of the relational operators via rewriting.

If you default <=> without defaulting ==, then the system will also generate a default ==, so defaulting <=> alone gives you all of the comparison operators.

Idyllic answered 10/11, 2020 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.