Section: 22.8.6.7 [expected.object.monadic], 22.5.3.8 [optional.monadic] Status: WP Submitter: Jiang An Opened: 2023-08-10 Last modified: 2023-11-22
Priority: Not Prioritized
View all other issues in [expected.object.monadic].
View all issues with WP status.
Discussion:
LWG 3938 switched to use **this
to access the value stored in std::expected
.
However, as shown in LWG 3969, **this
can trigger ADL and find an unwanted overload,
and thus may caused unintended behavior.
**this
, but use the name of the union member instead.
Moreover, P2407R5 will change the monadic operations of std::optional
to use **this
,
which is also problematic.
[2023-09-19; Wording update]
Several people preferred to replace operator*()
by the corresponding union members, so this part of the proposed wording
has been adjusted, which is a rather mechanical replacement.
[2023-10-30; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2023-11-11 Approved at November 2023 meeting in Kona. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4958.
Modify 22.8.6.7 [expected.object.monadic] as indicated:
[Drafting note: Effectively replace all occurrences of
**this
byval
, except fordecltype
.]
template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;-1- Let
-2- […] -3- […] -4- Effects: Equivalent to:U
beremove_cvref_t<invoke_result_t<F, decltype(
.**this(val))>>if (has_value()) return invoke(std::forward<F>(f),**thisval); 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
-6- […] -7- […] -8- Effects: Equivalent to:U
beremove_cvref_t<invoke_result_t<F, decltype((std::move(
.**thisval))>>if (has_value()) return invoke(std::forward<F>(f), std::move(**thisval)); 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
-10- Constraints:G
beremove_cvref_t<invoke_result_t<F, decltype(error())>>
.is_constructible_v<T, decltype(
is**this(val))>true
. -11- […] -12- Effects: Equivalent to:if (has_value()) return G(in_place,**thisval); 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
-14- Constraints:G
beremove_cvref_t<invoke_result_t<F, decltype(std::move(error()))>>
.is_constructible_v<T, decltype(std::move(
is**thisval))>true
. -15- […] -16- Effects: Equivalent to:if (has_value()) return G(in_place, std::move(**thisval)); 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
-18- […] -19- Mandates:U
beremove_cvref_t<invoke_result_t<F, decltype(
.**this(val))>>U
is a valid value type forexpected
. Ifis_void_v<U>
isfalse
, the declarationU u(invoke(std::forward<F>(f),**thisval));is well-formed.
-20- Effects:
(20.1) — […]
(20.2) — Otherwise, if
is_void_v<U>
isfalse
, returns anexpected<U, E>
object whosehas_val
member istrue
andval
member is direct-non-list-initialized withinvoke(std::forward<F>(f),
.**thisval)(20.3) — Otherwise, evaluates
invoke(std::forward<F>(f),
and then returns**thisval)expected<U, E>()
.template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;-21- Let
-22- […] -23- Mandates:U
beremove_cvref_t<invoke_result_t<F, decltype(std::move(
.**thisval))>>U
is a valid value type forexpected
. Ifis_void_v<U>
isfalse
, the declarationU u(invoke(std::forward<F>(f), std::move(**thisval)));is well-formed.
-24- Effects:
(24.1) — […]
(24.2) — Otherwise, if
is_void_v<U>
isfalse
, returns anexpected<U, E>
object whosehas_val
member istrue
andval
member is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(
.**thisval))(24.3) — Otherwise, evaluates
invoke(std::forward<F>(f), std::move(
and then returns**thisval))expected<U, E>()
.template<class F> constexpr auto transform_error(F&& f) &; template<class F> constexpr auto transform_error(F&& f) const &;-25- Let
-26- Constraints:G
beremove_cvref_t<invoke_result_t<F, decltype(error())>>
.is_constructible_v<T, decltype(
is**this(val))>true
. -27- Mandates: […] -28- Returns: Ifhas_value()
istrue
,expected<T, G>(in_place,
; otherwise, an**thisval)expected<T, G>
object whosehas_val
member isfalse
andunex
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
-30- Constraints:G
beremove_cvref_t<invoke_result_t<F, decltype(std::move(error()))>>
.is_constructible_v<T, decltype(std::move(
is**thisval))>true
. -31- Mandates: […] -32- Returns: Ifhas_value()
istrue
,expected<T, G>(in_place, std::move(
; otherwise, an**thisval))expected<T, G>
object whosehas_val
member isfalse
andunex
member is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(error()))
.
Modify 22.5.3.8 [optional.monadic] as indicated:
[Drafting note: Effectively replace all occurrences of
value()
by*val
.]
template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;-1- Let
-2- […] -3- Effects: Equivalent to:U
beinvoke_result_t<F, decltype(
.value()*val)>if (*this) { return invoke(std::forward<F>(f),value()*val); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;-4- Let
-5- […] -6- Effects: Equivalent to:U
beinvoke_result_t<F, decltype(std::move(
.value()*val))>if (*this) { return invoke(std::forward<F>(f), std::move(value()*val)); } else { return remove_cvref_t<U>(); }template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) const &;-7- Let
-8- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype(
.value()*val)>>U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f),value()*val));is well-formed for some invented variable
[…] -9- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f),
; otherwise,value()*val)optional<U>()
.template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;-10- Let
-11- Mandates:U
beremove_cv_t<invoke_result_t<F, decltype(std::move(
.value()*val))>>U
is a non-array object type other thanin_place_t
ornullopt_t
. The declarationU u(invoke(std::forward<F>(f), std::move(value()*val)));is well-formed for some invented variable
[…] -12- Returns: Ifu
.*this
contains a value, anoptional<U>
object whose contained value is direct-non-list-initialized withinvoke(std::forward<F>(f), std::move(
; otherwise,value()*val))optional<U>()
.