This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
std::bad_expected_access
Section: 22.8.4 [expected.bad], 22.8.5 [expected.bad.void], 22.8.6.6 [expected.object.obs], 22.8.7.6 [expected.void.obs] Status: New Submitter: Jiang An Opened: 2022-03-24 Last modified: 2024-07-24
Priority: 2
View all issues with New status.
Discussion:
The move constructor and the move assignment operator of standard exception types are not covered by
17.9.3 [exception]/2, and thus it is currently effectively unspecified whether these move
functions of std::bad_expected_access<void>
are noexcept
. Furthermore,
std::bad_expected_access<void>
has protected special member functions, which overrides
(or conflicts with?) the general rule in 17.9.3 [exception]/2.
std::bad_expected_access<E>
stores an E
object, and copying
the stored object may throw an exception. Is it intended that the copy functions of
std::bad_expected_access<E>
are noexcept
while those of E
are not?
When the copy happens because a std::bad_expected_access<E>
is caught by value, if the
copy constructor of E
throws, std::terminate
is called no matter whether that of
std::bad_expected_access<E>
is noexcept
. But
std::bad_expected_access<E>
may be copied/moved in other circumstances.
I think the move constructor and the move assignment operator of a standard exception type should be
specified to be public and noexcept
when they exist, although sometimes whether they exist may be
unspecified. And the move functions should also propagate the result of what()
when the source
and target have the same dynamic type, except that they can leave the result of what()
from
the source valid but unspecified.
Related to this, std::expected<T, E>::value
overloads are specified to throw
std::bad_expected_access<std::decay_t<E>>
when an E
is contained.
However, it seems that the copy constructor of std::bad_expected_access
is implicitly
deleted if E
is move-only, so the throw-expression is ill-formed.
Is it intended that std::expected<T, E>::value
is ill-formed in such cases?
[2022-05-17; Reflector poll]
Set priority to 2 after reflector poll.
[2023-05-25; Jonathan comments]
The last part was clarified by LWG 3843(i), confirming that
value()
is ill-formed for move-only E
.
[2024-07-24; Jonathan comments]
LWG 4031(i) made the move (and copy) operations of
bad_expected_access<void>
non-throwing.
Proposed resolution: