C++ Logo

std-proposals

Advanced search

clarifying monadic operations of std::expected proposal

From: Desmond Gold Bongcawel <desmondbongcawel922_at_[hidden]>
Date: Sun, 2 Jan 2022 20:42:15 +0800
While reading this paper https://wg21.link/P2505, I have found out some
"ambiguity" specifically in wording "or_else" member function in both
primary template and void partial specialization of std::expected.

From:

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

*Constraints:* F models invocable<> and E models copy_constructible.

*Mandates:* is_same_v<remove_cvref_t<invoke_result_t<F>>, expected> is true.

*Effects:* Equivalent to:

if (*this) {
    return *this;
} else {
   return invoke(std::forward<F>(f)(error()));
}

1 template <class F> constexpr expected or_else(F&& f) &&;

*Constraints:* F models invocable<> and E models move_constructable

*Mandates:* is_same_v<remove_cvref_t<invoke_result_t<F>>, expected> is true.

*Effects:* Equivalent to:

if (*this) {
   return std::move(*this);
}else {
   return invoke(std::forward<F>(f)(std::move(error())));
}

What does invoke(std::forward<F>(f)(error())) or
invoke(std::forward<F>(f)(std::move(error()))) mean in this case? While
from void partial specialization of std::expected:

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

*Constraints:* F models invocable<> and E models copy_constructible.

*Effects:* Equivalent to:

if (*this) {
    return *this;
} else {
   return invoke(std::forward<F>(f)());
}

1 template <class F> constexpr expected or_else(F&& f) &&;

*Constraints:* F models invocable<> and E models move_constructible.

*Effects:* Equivalent to:

if (*this) {
   return std::move(*this);
}else {
   return invoke(std::forward<F>(f)());
}

Does or_else member function need invocable that takes *nothing* (nullary)
or takes from *current** object's error()* ?
There are three possible solutions to solve:
1.) Constrain such that F models invocable<> and the expression
invoke(std::forward<F>(f)) is used inside else-block (no parameter)
2.) Constrain such that F models invocable<*cv* error_type *ref*> and the
expression invoke(std::forward<F>(f), error()) for l-value ref
overlads or invoke(std::forward<F>(f),
std::move(error())) for r-value ref overloads.
3.) Combine the first two solutions.

Received on 2022-01-02 06:42:30