C++ Logo


Advanced search

Re: Yet another member function for std::map

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Mon, 2 Aug 2021 10:59:48 -0400
On Mon, Aug 2, 2021 at 10:36 AM Barry Revzin via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> On Mon, Aug 2, 2021 at 9:29 AM Ville Voutilainen via Std-Proposals <std-proposals_at_[hidden]> wrote:
>> On Mon, 2 Aug 2021 at 17:18, Jason McKesson via Std-Proposals
>> <std-proposals_at_[hidden]> wrote:
>> >
>> > On Mon, Aug 2, 2021 at 6:26 AM Andrey Semashev via Std-Proposals
>> > <std-proposals_at_[hidden]> wrote:
>> > >
>> > > On 8/2/21 12:28 PM, Lénárd Szolnoki via Std-Proposals wrote:
>> > > >
>> > > > The Achilles' heel of optional<T&> seems to be assignment. I'm of the
>> > > > opinion that it simply shouldn't have assignment from arguments of type
>> > > > T, but I believe there is no perfect answer.
>> > >
>> > > Personally, I have no problem with rebinding semantics of
>> > > optional<T&>::operator=(T&). That it would affect the referred object
>> > > makes no sense because (a) there may not be such an object (if the
>> > > optional is empty) and (b) no other version of optional<T> acts this
>> > > way.
>> >
>> > Um, yes they do. If you have an engaged `optional<T>`, and you assign
>> > a `T` to it, it assigns to the engaged value. It does not
>> > unengage/re-engage itself.
>> >
>> > So if you have this:
>> >
>> > ```
>> > optional<T> t = ...; //some T
>> > T& t_ref = *t;
>> > t = ...; //some other T
>> > ```
>> >
>> > If each of those pieces of code is valid, then `t_ref` is also valid.
>> > It still refers to the value you assigned to the `t`.
>> >
>> > The semantics you want for `optional<T&>` violate this. The `t_ref` in
>> > this case would refer to the old referenced object, not the new one.
>> That, to me, seems like an almost "of course" level reason for having
>> the assignment "assign through" if
>> an optional<T&> is engaged. If it's engaged, it invokes the assignment
>> of the held entity, and if that has reference
>> semantics, so be it.
> Except it's the wrong semantic, which is why precisely zero implementations of optional that support references (and there are several) do this. And it's the wrong semantic because it has wildly different behavior based on initial state, and thus basically has no meaningful semantic behavior that you can rely on. Something something standardizing a wealth of existing practice.
> The right semantic is the assignment does actually do "unengage/re-engage" and the right way to think about it is that optional already does this. Except that since for many types, assignment can be much more efficient then destroy/construct, we defer to the assignment operator. It's just that for references, we know that this is wrong, so we can avoid doing it.

I think that's the core of the problem here: the "right semantic" for
references is *not* the "right semantic" for *values*. It makes
absolutely no sense for assignment to an optional value type to
unengage/re-engage. Values are values, and if a value is assignable,
then assigning to it has a clear and unambiguous meaning.

If you want to have `optional<T&>`'s assignment behave this way, then
it's clear that it cannot be *spelled* `optional<T&>`. This is for the
same reason that `vector<bool>`s mistake is that it's called "vector".
`vector`'s are supposed to have specific behavior, and `vector<bool>`
doesn't follow that. Same goes for `optional<T>`: it has specific,
reasonable behavior which `optional<T&>` wouldn't have.

If you believe that this is the right semantic for references, then it
needs to be a separate class from optional values.

Received on 2021-08-02 10:00:08