Date: Tue, 3 Dec 2024 10:30:37 -0600
On Sun, Dec 1, 2024 at 10:06 AM Andrey Semashev via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On December 1, 2024 8:34:55 AM Arthur O'Dwyer via Std-Proposals
> <std-proposals_at_[hidden]> 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
std-proposals_at_[hidden]> wrote:
> On December 1, 2024 8:34:55 AM Arthur O'Dwyer via Std-Proposals
> <std-proposals_at_[hidden]> 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
Received on 2024-12-03 16:30:51