This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++26 status.
Section: 22.8.6.7 [expected.object.monadic], 22.5.3.8 [optional.monadic] Status: C++26 Submitter: Jiang An Opened: 2023-08-10 Last modified: 2026-06-09
Priority: Not Prioritized
View all other issues in [expected.object.monadic].
View all issues with C++26 status.
Discussion:
LWG 3938(i) switched to use **this to access the value stored in std::expected.
However, as shown in LWG 3969(i), **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
**thisbyval, except fordecltype.]
templateconstexpr auto and_then(F&& f) &; template constexpr auto and_then(F&& f) const &; -1- Let
-2- […] -3- […] -4- Effects: Equivalent to:Uberemove_cvref_t.**this(val))>> if (has_value()) return invoke(std::forward(f), **thisval); else return U(unexpect, error());templateconstexpr auto and_then(F&& f) &&; template constexpr auto and_then(F&& f) const &&; -5- Let
-6- […] -7- […] -8- Effects: Equivalent to:Uberemove_cvref_t.**thisval))>> if (has_value()) return invoke(std::forward(f), std::move( **thisval)); else return U(unexpect, std::move(error()));templateconstexpr auto or_else(F&& f) &; template constexpr auto or_else(F&& f) const &; -9- Let
-10- Constraints:Gberemove_cvref_t.> is_constructible_vis**this(val))> true. -11- […] -12- Effects: Equivalent to:if (has_value()) return G(in_place,**thisval); else return invoke(std::forward(f), error()); templateconstexpr auto or_else(F&& f) &&; template constexpr auto or_else(F&& f) const &&; -13- Let
-14- Constraints:Gberemove_cvref_t.> is_constructible_vis**thisval))> true. -15- […] -16- Effects: Equivalent to:if (has_value()) return G(in_place, std::move(**thisval)); else return invoke(std::forward(f), std::move(error())); templateconstexpr auto transform(F&& f) &; template constexpr auto transform(F&& f) const &; -17- Let
-18- […] -19- Mandates:Uberemove_cvref_t.**this(val))>> Uis a valid value type forexpected. Ifis_void_visfalse, the declarationU u(invoke(std::forward(f), **thisval));is well-formed.
-20- Effects:
(20.1) — […]
(20.2) — Otherwise, if
is_void_visfalse, returns anexpectedobject whosehas_valmember istrueandvalmember is direct-non-list-initialized withinvoke(std::forward.(f), **thisval)(20.3) — Otherwise, evaluates
invoke(std::forwardand then returns(f), **thisval)expected().templateconstexpr auto transform(F&& f) &&; template constexpr auto transform(F&& f) const &&; -21- Let
-22- […] -23- Mandates:Uberemove_cvref_t.**thisval))>> Uis a valid value type forexpected. Ifis_void_visfalse, the declarationU u(invoke(std::forward(f), std::move( **thisval)));is well-formed.
-24- Effects:
(24.1) — […]
(24.2) — Otherwise, if
is_void_visfalse, returns anexpectedobject whosehas_valmember istrueandvalmember is direct-non-list-initialized withinvoke(std::forward.(f), std::move( **thisval))(24.3) — Otherwise, evaluates
invoke(std::forwardand then returns(f), std::move( **thisval))expected().templateconstexpr auto transform_error(F&& f) &; template constexpr auto transform_error(F&& f) const &; -25- Let
-26- Constraints:Gberemove_cvref_t.> is_constructible_vis**this(val))> true. -27- Mandates: […] -28- Returns: Ifhas_value()istrue,expected; otherwise, an(in_place, **thisval)expectedobject whosehas_valmember isfalseandunexmember is direct-non-list-initialized withinvoke(std::forward.(f), error()) templateconstexpr auto transform_error(F&& f) &&; template constexpr auto transform_error(F&& f) const &&; -29- Let
-30- Constraints:Gberemove_cvref_t.> is_constructible_vis**thisval))> true. -31- Mandates: […] -32- Returns: Ifhas_value()istrue,expected; otherwise, an(in_place, std::move( **thisval))expectedobject whosehas_valmember isfalseandunexmember is direct-non-list-initialized withinvoke(std::forward.(f), std::move(error()))
Modify 22.5.3.8 [optional.monadic] as indicated:
[Drafting note: Effectively replace all occurrences of
value()by*val.]
templateconstexpr auto and_then(F&& f) &; template constexpr auto and_then(F&& f) const &; -1- Let
-2- […] -3- Effects: Equivalent to:Ubeinvoke_result_t.value()*val)> if (*this) { return invoke(std::forward(f), value()*val); } else { return remove_cvref_t(); }templateconstexpr auto and_then(F&& f) &&; template constexpr auto and_then(F&& f) const &&; -4- Let
-5- […] -6- Effects: Equivalent to:Ubeinvoke_result_t.value()*val))> if (*this) { return invoke(std::forward(f), std::move( value()*val)); } else { return remove_cvref_t(); }templateconstexpr auto transform(F&& f) &; template constexpr auto transform(F&& f) const &; -7- Let
-8- Mandates:Uberemove_cv_t.value()*val)>> Uis a non-array object type other thanin_place_tornullopt_t. The declarationU u(invoke(std::forward(f), value()*val));is well-formed for some invented variable
[…] -9- Returns: Ifu.*thiscontains a value, anoptionalobject whose contained value is direct-non-list-initialized withinvoke(std::forward; otherwise,(f), value()*val)optional().templateconstexpr auto transform(F&& f) &&; template constexpr auto transform(F&& f) const &&; -10- Let
-11- Mandates:Uberemove_cv_t.value()*val))>> Uis a non-array object type other thanin_place_tornullopt_t. The declarationU u(invoke(std::forward(f), std::move( value()*val)));is well-formed for some invented variable
[…] -12- Returns: Ifu.*thiscontains a value, anoptionalobject whose contained value is direct-non-list-initialized withinvoke(std::forward; otherwise,(f), std::move( value()*val))optional().