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:
- (20.1) — If
has_value()isfalse, returnsexpected<U, E>(unexpect, error()). - (20.2) — Otherwise, if
is_void_v<U>isfalse, returns anexpected<U, E>object whose_hasval_member istrueand_val_member is direct-non-list-initialized withinvoke(std::forward<F>(f), ~~value()~~**this). - (20.3) — Otherwise, evaluates
invoke(std::forward<F>(f), ~~value()~~**this)and then returnsexpected<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:
- (24.1) — If
has_value()isfalse, returnsexpected<U, E>(unexpect, error()). - (24.2) — Otherwise, if
is_void_v<U>isfalse, returns anexpected<U, E>object whose_hasval_member istrueand_val_member is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(~~value()~~**this)). - (24.3) — Otherwise, evaluates
invoke(std::forward<F>(f), std::move(~~value()~~**this))and then returnsexpected<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())).