C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Should postfix increment and decrement operators be automatically obtainable from their prefix versions?

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Wed, 24 Jan 2024 14:21:49 -0500
On Wed, Jan 24, 2024 at 10:50 AM Matthew Taylor via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> I did see that paper, but it took a different approach from my proposed
> one. P1046 suggested automatically generating both operator++ overloads in
> terms of an addition operator as equivalent to foo += 1.
>

That's not quite right.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1046r2.html
proposes:
    A& operator++() = default;
should generate a body like `{ *this += 1; return *this; }`, but we don't
expect ordinary programmers will often =default the prefix operator (and as
you point out, it flatly *would be ill-formed* to =default it in many
cases). At the same time,
    A operator++(int) = default;
should generate a body like `{ auto copy = *this; ++*this; return copy; }`
— the exact implementation includes a case for non-copyable A, and is given
in the paper. Ctrl+F `[&]`.

To Jan's point about matrices: P1046 also rightly points out that instead
of generating `*` from `*=`, it's better to generate `*=` from (a properly
move-semantified) `*`. Details in the paper.

I'd say it mirrors that changes to the equality operators in C++20. In
> current C++, should you decide to define operator== for your class (or of
> course operator<=>) then you automatically get an implicitly-generated
> operator!= which returns the negation of the result of operator== for those
> types.
>

That's not quite right, and points the way to an alternative design (which
I believe is the design being pursued for "autogenerated operator->" in
P1046R3-or-whatever-it-becomes). C++20 never implicitly generates a
defaulted `operator!=` for any class type. Instead, C++20 includes
expression rewrite rules such that the expression
    (a != b)
 is allowed to work like any of the following:
    operator!=(a, b)
    a.operator!=(b)
    !(operator==(a, b)) // New in C++20!
    !(a.operator==(b)) // New in C++20!
    !(operator==(b, a)) // New in C++20!
    !(b.operator==(a)) // New in C++20!
in roughly decreasing order of preference.

We could similarly propose for C++Future that the expression
    a++
should work like any of the following:
    a.operator++(1)
    [&]{ auto copy = a; a.operator++(); return copy; }() // New in
C++Future!
    [&]{ a.operator++(); }() // New in C++Future!
This wouldn't involve autogenerating any defaulted operators; it would just
make `a++` a valid expression in more cases.

Expression-rewriting seems to be cheaper than generating-and-calling
defaulted functions; it might be the Way of the Future. Or I might just be
reading too much into a single data point (spaceship). :)

But anyway, your proposal is really exactly (a subset of) P1046R2, so you
should definitely find out more about where P1046 is going next, and why
the bits that failed failed, rather than start work on a completely
parallel proposal.

HTH,
Arthur

Received on 2024-01-24 19:22:04