3877. Incorrect constraints on const-qualified monadic overloads for std::expected

Section: 22.8.6.7 [expected.object.monadic], 22.8.7.7 [expected.void.monadic] Status: C++23 Submitter: Sy Brand Opened: 2023-02-09 Last modified: 2023-11-22

Priority: Not Prioritized

View all other issues in [expected.object.monadic].

View all issues with C++23 status.

Discussion:

The constraints for and_then, transform, transform_error, and or_else for std::expected seem incorrect for const overloads. E.g., from 22.8.6.7 [expected.object.monadic]

template<class F> constexpr auto transform(F&& f) &&;
template<class F> constexpr auto transform(F&& f) const &&;
[…]

Constraints: is_move_constructible_v<E> is true.

That constraint should likely be is_move_constructible_v<const E> for the const-qualified version. Same for the lvalue overloads, and for the three other functions, including in the void partial specialization. For example, currently this code would result in a hard compiler error inside the body of transform rather than failing the constraint:

const std::expected<int, std::unique_ptr<int>> e;
std::move(e).transform([](auto) { return 42; });

Previous resolution [SUPERSEDED]:

This wording is relative to N4928.

  1. Modify 22.8.6.7 [expected.object.monadic] as indicated:

    template<class F> constexpr auto and_then(F&& f) &;
    template<class F> constexpr auto and_then(F&& f) const &;
    

    […]

    -2- Constraints: is_copy_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto and_then(F&& f) &&;
    template<class F> constexpr auto and_then(F&& f) const &&;
    

    […]

    -6- Constraints: is_move_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto or_else(F&& f) &;
    template<class F> constexpr auto or_else(F&& f) const &;
    

    […]

    -10- Constraints: is_copy_constructible_v<Tdecltype((value()))> is true.

    […]

    template<class F> constexpr auto or_else(F&& f) &&;
    template<class F> constexpr auto or_else(F&& f) const &&;
    

    […]

    -14- Constraints: is_move_constructible_v<Tdecltype((value()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &;
    template<class F> constexpr auto transform(F&& f) const &;
    

    […]

    -18- Constraints: is_copy_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &&;
    template<class F> constexpr auto transform(F&& f) const &&;
    

    […]

    -22- Constraints: is_move_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto transform_error(F&& f) &;
    template<class F> constexpr auto transform_error(F&& f) const &;
    

    […]

    -26- Constraints: is_copy_constructible_v<Tdecltype((value()))> is true.

    […]

    template<class F> constexpr auto transform_error(F&& f) &&;
    template<class F> constexpr auto transform_error(F&& f) const &&;
    

    […]

    -30- Constraints: is_move_constructible_v<Tdecltype((value()))> is true.

  2. Modify 22.8.7.7 [expected.void.monadic] as indicated:

    template<class F> constexpr auto and_then(F&& f) &;
    template<class F> constexpr auto and_then(F&& f) const &;
    

    […]

    -2- Constraints: is_copy_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto and_then(F&& f) &&;
    template<class F> constexpr auto and_then(F&& f) const &&;
    

    […]

    -6- Constraints: is_move_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &;
    template<class F> constexpr auto transform(F&& f) const &;
    

    […]

    -16- Constraints: is_copy_constructible_v<Edecltype((error()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &&;
    template<class F> constexpr auto transform(F&& f) const &&;
    

    […]

    -20- Constraints: is_move_constructible_v<Edecltype((error()))> is true.

    […]

[Issaquah 2023-02-09; Jonathan provides improved wording]

[Issaquah 2023-02-09; LWG]

Move to Immediate for C++23

[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]

Proposed resolution:

This wording is relative to N4928.

  1. Modify 22.8.6.7 [expected.object.monadic] as indicated:

    template<class F> constexpr auto and_then(F&& f) &;
    template<class F> constexpr auto and_then(F&& f) const &;
    

    […]

    -2- Constraints: is_copy_constructible_v<E, decltype(error())> is true.

    […]

    template<class F> constexpr auto and_then(F&& f) &&;
    template<class F> constexpr auto and_then(F&& f) const &&;
    

    […]

    -6- Constraints: is_copy_constructible_v<E, decltype(std::move(error()))> is true.

    […]

    template<class F> constexpr auto or_else(F&& f) &;
    template<class F> constexpr auto or_else(F&& f) const &;
    

    […]

    -10- Constraints: is_copy_constructible_v<T, decltype(value())> is true.

    […]

    template<class F> constexpr auto or_else(F&& f) &&;
    template<class F> constexpr auto or_else(F&& f) const &&;
    

    […]

    -14- Constraints: is_copy_constructible_v<T, decltype(std::move(value()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &;
    template<class F> constexpr auto transform(F&& f) const &;
    

    […]

    -18- Constraints: is_copy_constructible_v<E, decltype(error())> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &&;
    template<class F> constexpr auto transform(F&& f) const &&;
    

    […]

    -22- Constraints: is_copy_constructible_v<E, decltype(std::move(error()))> is true.

    […]

    template<class F> constexpr auto transform_error(F&& f) &;
    template<class F> constexpr auto transform_error(F&& f) const &;
    

    […]

    -26- Constraints: is_copy_constructible_v<T, decltype(value())> is true.

    […]

    template<class F> constexpr auto transform_error(F&& f) &&;
    template<class F> constexpr auto transform_error(F&& f) const &&;
    

    […]

    -30- Constraints: is_copy_constructible_v<T, decltype(std::move(value()))> is true.

  2. Modify 22.8.7.7 [expected.void.monadic] as indicated:

    template<class F> constexpr auto and_then(F&& f) &;
    template<class F> constexpr auto and_then(F&& f) const &;
    

    […]

    -2- Constraints: is_copy_constructible_v<E, decltype(error())> is true.

    […]

    template<class F> constexpr auto and_then(F&& f) &&;
    template<class F> constexpr auto and_then(F&& f) const &&;
    

    […]

    -6- Constraints: is_copy_constructible_v<E, decltype(std::move(error()))> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &;
    template<class F> constexpr auto transform(F&& f) const &;
    

    […]

    -16- Constraints: is_copy_constructible_v<E, decltype(error())> is true.

    […]

    template<class F> constexpr auto transform(F&& f) &&;
    template<class F> constexpr auto transform(F&& f) const &&;
    

    […]

    -20- Constraints: is_copy_constructible_v<E, decltype(std::move(error()))> is true.

    […]