On Mon, Aug 2, 2021 at 9:29 AM Ville Voutilainen via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Mon, 2 Aug 2021 at 17:18, Jason McKesson via Std-Proposals
<std-proposals@lists.isocpp.org> wrote:
> On Mon, Aug 2, 2021 at 6:26 AM Andrey Semashev via Std-Proposals
> <std-proposals@lists.isocpp.org> 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.