C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Dummy value protocol

From: Avi Kivity <avi_at_[hidden]>
Date: Sat, 07 Jun 2025 20:48:45 +0300
On Sat, 2025-06-07 at 19:15 +0200, Jan Schultke wrote:
> > Why wouldn't it work with fundamental types?
> > I explicitly marked them as supporting the protocol. Maybe I did a
> > bad job of explaining myself.
>
> Because every possible value of type int is not an empty
> std::optional
> when you put it into std::optional already. You cannot define int(-1)
> to be an empty std::optional after the fact, so you're stuck with
> effectively storing an extra bool.
>
> This behavior can obviously not be changed at this point.


But that is not my proposal. std::optional keeps its bool flag. The
difference is in how the special member functions are generated:


std::optional<T>::~optional() {
    if constexpr (uses the dummy protocol) {
         _value->~T();
    } else {
        if (_engaged) {
             _value->~T();
        }
    }
}

We avoided a conditional. For fundamental types, we didn't win
anything, but (say) the move constructor becomes simpler:


std::optional<T>::optional(optional&& o) {
    // omitting exception safety
    if constexpr (uses the dummy protocol) {
         _engaged = std::exchange(o._engaged, false);
         _value = std::move(o._value);
    } else {
        _engaged = std::exchange(o._engaged, false);
        if (_engaged) {
             // Can be replaced with std::relocate_at()
             std::construct_at(&_value, std::move(o._value));
             std::destroy_at(&o._value);
        }
    }
}

For fundamental types, and for trivially relocatable types, moving an
optional becomes just data movement with no conditionals.


> On Sat, 7 Jun 2025 at 19:12, Avi Kivity <avi_at_[hidden]> wrote:
> >
> > Why wouldn't it work with fundamental types? I explicitly marked
> > them as supporting the protocol. Maybe I did a bad job of
> > explaining myself.
> >
> > And again some raises std::expected, it's not related. This is for
> > every container that can conditionally carry a value, std::optional
> > is the best example but I encountered the problem while working on
> > a different class (an interval type).
> >
> > On Sat, 2025-06-07 at 13:24 +0200, Jan Schultke wrote:
> >
> > I don't think it's worth the effort if it cannot work for
> > fundamental
> > types, and the ABI for std::optional is set in stone. Ideally, we
> > would be able to say that std::optional<X*> where nullptr stores
> > the
> > empty value, or std::optional<int> where -1 represents an empty
> > value,
> > etc.
> >
> > Those things seem feasible with std::expected with a bit of library
> > support. We could have something like
> >
> > std::expected<int, std::nonvalue<-1>>
> >
> >
> > Which would use the value "-1" to represent an unexpected object.
> > This
> > would also not break any existing code since it would use novel
> > types
> > and a novel protocol, even in the case of fundamental types.
> >
> >

Received on 2025-06-07 17:48:49