3866. Bad Mandates for expected::transform_error overloads

Section: 22.8.6.7 [expected.object.monadic], 22.8.7.7 [expected.void.monadic] Status: C++23 Submitter: Casey Carter Opened: 2023-01-29 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 overloads of expected::transform_error mandate that "[type] G is a valid value type for expected" (22.8.6.7 [expected.object.monadic]/27 and 31 as well as 22.8.7.7 [expected.void.monadic]/24 and 27)).

All of these overloads then instantiate expected<T, G> (for some type T) which doesn't require G to be a valid value type for expected (22.8.6.1 [expected.object.general]/2) but instead requires that G is "a valid template argument for unexpected" (22.8.6.1 [expected.object.general]/2). Comparing 22.8.6.1 [expected.object.general]/2 with 22.8.3.1 [expected.un.general]/2 it's clear that there are types — const int, for example — which are valid value types for expected but not valid template arguments for unexpected. Presumably this unimplementable requirement is a typo, and the subject paragraphs intended to require that G be a valid template argument for unexpected.

[2023-02-06; Reflector poll]

Set status to Tentatively Ready after five votes in favour during reflector poll.

[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Voting → 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 transform_error(F&& f) &;
    template<class F> constexpr auto transform_error(F&& f) const &;
    

    […]

    -27- Mandates: G is a valid value type for expectedtemplate argument for unexpected (22.8.3.1 [expected.un.general]) and the declaration

    G g(invoke(std::forward<F>(f), error()));
    

    is well-formed.

    […]

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

    […]

    -31- Mandates: G is a valid value type for expectedtemplate argument for unexpected (22.8.3.1 [expected.un.general]) and the declaration

    G g(invoke(std::forward<F>(f), std::move(error())));
    

    is well-formed.

    […]

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

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

    […]

    -24- Mandates: G is a valid value type for expectedtemplate argument for unexpected (22.8.3.1 [expected.un.general]) and the declaration

    G g(invoke(std::forward<F>(f), error()));
    

    is well-formed.

    […]

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

    […]

    -27- Mandates: G is a valid value type for expectedtemplate argument for unexpected (22.8.3.1 [expected.un.general]) and the declaration

    G g(invoke(std::forward<F>(f), std::move(error())));
    

    is well-formed.

    […]