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.

### 3688. Exception specifications of copy/move member functions of `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: 2022-05-17

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.10.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.10.3 [exception]/2.

The primary template `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.

Proposed resolution: