On December 1, 2024 8:34:55 AM Arthur O'Dwyer via Std-Proposals
<std-proposals@lists.isocpp.org> wrote:
> One of the drastic changes in P3039 was the idea that maybe instead of
> making
> auto operator->() const = default;
> define a new member function definition, we should simply add a rewrite
> rule just like the existing (C++20) rewrite rule for (a < b). We could say
> that (a -> b) will perform lookup for both (a.operator->) *and*
> (a.operator*) in exactly the same way that (a < b) performs lookup for both
> (a.operator<) *and* (a.operator<=>). (And add similar rules for deciding
> which candidate is the best match.)
>
> This would also influence your proposal about (a++): Should you actually
> make
> auto operator++(int) = default;
> define a new member function definition, or should you simply add a rewrite
> rule that makes (a++) perform lookup for both variants of operator++ and
> fall back to the prefix version (plus the copy constructor) if the postfix
> version isn't available? Your motivation touches on that question here:
>
> Would it not be nice to be able to just write
>> T operator++(int) = default;
>> and never have to bother with it again, just like you can write
>> bool operator!=(const T&, const T&) = default;
>> and get the expected result.
>
>
> You *can* write `operator!=(...) = default`, but no C++20 programmer ever
> *would* write it, because we have a rewrite rule that handles that
> transparently, without the programmer's intervention. So, it seems like it
> would make sense to handle postfix `++` in the same way, right?
FWIW, C++20 operator rewriting rules did break real world code,
specifically Boost.Operator, which remains broken under C++20 and later to
this day. This is one of the reasons why some code bases decided to remain
on C++17 and not upgrade. IMO, accepting those rules into the standard was
premature at best, entirely bad idea at worst.
This should be a cautionary tale for anyone suggesting more rewriting rules
in the standard.
This is why David Stone was asked to pare his paper down to just rewriting c->m to be (*c).m.
But that particular rewrite remains interesting both because operator->() is tedious to implement in the case where operator*() doesn't return an lvalue reference and also because the language rewrite could preserve value category which is otherwise destroyed by operator->(), so the rewrite would be strictly better than what you could write in code today. That is, for something like:
struct C { string s; };
auto f() -> optional<C>;
The expression f()->s today is an lvalue even though (*f()).s is an xvalue. The rewrite rule would allow the former to have the same meaning, which seems nice.
That's not true for postfix increment, which is always trivial (just repetitive) to implement and there's no added benefit available.
Barry