Issue 3938: Cannot use std::expected monadic ops with move-only error_type (original) (raw)

For each Effects: element in 22.8.6.7 [expected.object.monadic], replace value() with **this as indicated:


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

-1- Let U beremove_cvref_t<invoke_result_t<F, decltype(~~value()~~**this)>>.

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

-3- Mandates:U is a specialization of expected andis_same_v<U::error_type, E> is true.

-4- Effects: Equivalent to:

if (has_value())
 return invoke(std::forward<F>(f), value()**this);
else
 return U(unexpect, error());

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

-5- Let U beremove_cvref_t<invoke_result_t<F, decltype(std::move(~~value()~~**this))>>.

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

-7- Mandates:U is a specialization of expected andis_same_v<U::error_type, E> is true.

-8- Effects: Equivalent to:

if (has_value())
 return invoke(std::forward<F>(f), std::move(value()**this));
else
 return U(unexpect, std::move(error()));

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

-9- Let G beremove_cvref_t<invoke_result_t<F, decltype(error())>>.

-10- Constraints:is_constructible_v<T, decltype(~~value()~~**this)>is true.

-11- Mandates:G is a specialization of expected andis_same_v<G::value_type, T> is true.

-12- Effects: Equivalent to:

if (has_value())
 return G(in_place, value()**this);
else
 return invoke(std::forward<F>(f), error());

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

-13- Let G beremove_cvref_t<invoke_result_t<F, decltype(std::move(error()))>>.

-14- Constraints:is_constructible_v<T, decltype(std::move(~~value()~~**this))>is true.

-15- Mandates:G is a specialization of expected andis_same_v<G::value_type, T> is true.

-16- Effects: Equivalent to:

if (has_value())
 return G(in_place, std::move(value()**this));
else
 return invoke(std::forward<F>(f), std::move(error()));

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

-17- Let U beremove_cv_t<invoke_result_t<F, decltype(~~value()~~**this)>>.

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

-19- Mandates:U is a valid value type for expected. If is_void_v<U> is false, the declaration

  U u(invoke(std::forward<F>(f), value()**this));

is well-formed.

-20- Effects:

  1. (20.1) — If has_value() is false, returns expected<U, E>(unexpect, error()).
  2. (20.2) — Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose_hasval_ member is true and_val_ member is direct-non-list-initialized withinvoke(std::forward<F>(f), ~~value()~~**this).
  3. (20.3) — Otherwise, evaluatesinvoke(std::forward<F>(f), ~~value()~~**this)and then returns expected<U, E>().

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

-21- Let U beremove_cv_t<invoke_result_t<F, decltype(std::move(~~value()~~**this))>>.

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

-23- Mandates:U is a valid value type for expected. If is_void_v<U> is false, the declaration

  U u(invoke(std::forward<F>(f), std::move(value()**this)));

is well-formed for some invented variable u.

[_Drafting Note:_The removal of "for some invented variable u" in paragraph 23 is a drive-by fix for consistency with paragraphs 19, 27 and 31.]

-24- Effects:

  1. (24.1) — If has_value() is false, returns expected<U, E>(unexpect, error()).
  2. (24.2) — Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose_hasval_ member is true and_val_ member is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(~~value()~~**this)).
  3. (24.3) — Otherwise, evaluatesinvoke(std::forward<F>(f), std::move(~~value()~~**this))and then returns expected<U, E>().

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

-25- Let G beremove_cv_t<invoke_result_t<F, decltype(error())>>.

-26- Constraints:is_constructible_v<T, decltype(~~value()~~**this)>is true.

-27- Mandates:G is a valie template argument for unexpected( [unexpected.un.general]) and the declaration

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

is well-formed.

-28- Returns: If has_value() is true,expected<T, G>(in_place, ~~value()~~**this);; otherwise, an expected<T, G> object whose_hasval_ member is falseand _unex_ member is direct-non-list-initialized withinvoke(std::forward<F>(f), error()).


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

-29- Let G beremove_cv_t<invoke_result_t<F, decltype(std::move(error()))>>.

-30- Constraints:is_constructible_v<T, decltype(std::move(~~value()~~**this))>is true.

-31- Mandates:G is a valie template argument for unexpected( [unexpected.un.general]) and the declaration

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

is well-formed.

-32- Returns: If has_value() is true,expected<T, G>(in_place, std::move(~~value()~~**this));; otherwise, an expected<T, G> object whose_hasval_ member is falseand _unex_ member is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(error())).