C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Suggeting improvements to std::expected<T, std::exception_ptr>

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Mon, 31 Mar 2025 22:51:43 +0100
On Mon, 31 Mar 2025 at 22:33, Stewart Becker via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Thank you, Jonathan, for your insights.
> On 31/03/2025 09:42, Jonathan Wakely wrote:
>
> std::optional<T&> is explicitly not allowing rvalue references, I don't
> see the committee going the other way for std::expected.
>
> Maybe I missed something, but P2988 doesn't seem to mention rvalue
> references, neither proposing nor actively disallowing them. Has there
> been any discussion on std::optional<T&&> at all, or it simply not (yet)
> proposed?
>

 P2988R6 included a partial specialization for optional<T&&>, but P2988R7
dropped it again. The paper doesn't say why, and the minutes are vague. I
thought it had been discussed and rejected, but it seems that it was just
dropped so that the optional<T&> form could make progress without getting
coupled to a more novel specialization that hasn't been properly designed
yet.



> P2988's given rationale for optional<T&> is that any type that
> std::tuple accepts should work with std::variant (and by extension, work
> with std::optional and std::expected). As std::tuple supports both lvalue
> and rvalue references, perhaps allowing rvalue references for both
> std::optional and std::expected (and std::variant?) is a potential next
> step.
>
>
>
>> 1. std::exception_ptr::value() called std::rethrow_exception(error())
>> rather than throwing a std::bad_expected_access on error, and
>>
>>
> What if the error() is a null std::exception_ptr? The rethrow would have
> undefined behaviour in that case.
>
> Good point.
>
> As nice as some of these changes might be, they would mean ABI breaks if
> we did it now. For std::expected<T&, exception_ptr> we could do anything,
> because that doesn't exist now so there's no compatibility with existing
> code to worry about. But it would be strange if it had a completely
> different API from the non-reference std::expected<T, exception_ptr> form.
>
> One solution would be to introduce a tag type that can be used as the
> second template argument to request the behaviour you want, e.g.
> std::expected<T, std::handle_exceptions_cleverly>, but with a better name
> :-)
> That tag type doesn't exist today, so there would be no compatibility
> concerns here either. Anybody using the tag type is explicitly opting in to
> the alternative API. The error_type could still be defined as
> exception_ptr, rather than the tag type, and the monadic operations could
> be modified to catch exceptions from the callable. Something like a tag
> type was the (weakly) preferred direction for P3014
>
> If I understand you correctly, specialising std::expected<T, new_tag_type>
> would be acceptable on the basis that new_tag_type is *new*, rather than
> because it is a tag type *per se*.
>
Right. Nobody is using std::expected<T, new_tag_type> today, because
std::new_tag_type doesn't exist so they *can't* be using it today. So we
can give that specialization whatever new semantics we want, because it
can't break anybody's code.

> The downside of a tag type is that it breaks the pattern of the type
> parameters <T, E> denoting the types <value_type, error type>. But what if
> we specialise std::expected on a new *error* type
> std::non_null_exception_ptr? I think this resolves the issue of ABI
> compatibility and avoids the problem of a null error_type. There's even a
> reasonably good name for it :-)
>

Maybe std::exception_ref, if it's a non-nullable pointer!

Received on 2025-03-31 21:52:00