Skip to content

Commit db63962

Browse files
committed
st: P13 - rvalue overloads for Expected monadic ops and value_or
value_or, and_then, transform, and or_else were const&-only: they copied the contained value into the continuation, and value_or/and_then/transform would not even compile for a move-only T. Add &&-qualified overloads that move the contained value (and forward the error by move), so a move-only or expensive-to-copy T flows through the chain without a copy. value() and operator* already had ref-qualified overloads. Verified at runtime with a move-only payload (unique_ptr) on clang and gcc, plus an lvalue regression pass. Signed-off-by: Matteo Merli <mmerli@apache.org>
1 parent 9999a4a commit db63962

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

include/pulsar/st/Expected.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ class [[nodiscard]] Expected {
184184
return has_value() ? std::get<0>(storage_) : static_cast<T>(std::forward<U>(fallback));
185185
}
186186

187+
/** Rvalue overload of `value_or()`: moves the contained value out on success. */
188+
template <typename U>
189+
T value_or(U&& fallback) && {
190+
return has_value() ? std::get<0>(std::move(storage_)) : static_cast<T>(std::forward<U>(fallback));
191+
}
192+
187193
/**
188194
* Monadic chaining: invoke @p f on the value, or propagate the error.
189195
*
@@ -202,6 +208,13 @@ class [[nodiscard]] Expected {
202208
return has_value() ? std::forward<F>(f)(std::get<0>(storage_)) : R(error());
203209
}
204210

211+
/** Rvalue overload of `and_then()`: invokes @p f with the moved-out value. */
212+
template <typename F>
213+
auto and_then(F&& f) && {
214+
using R = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T&&>>>;
215+
return has_value() ? std::forward<F>(f)(std::get<0>(std::move(storage_))) : R(std::move(error()));
216+
}
217+
205218
/**
206219
* Monadic mapping: transform the value through @p f, or propagate the error.
207220
*
@@ -219,6 +232,14 @@ class [[nodiscard]] Expected {
219232
return has_value() ? Expected<U>(std::forward<F>(f)(std::get<0>(storage_))) : Expected<U>(error());
220233
}
221234

235+
/** Rvalue overload of `transform()`: maps the moved-out value through @p f. */
236+
template <typename F>
237+
auto transform(F&& f) && {
238+
using U = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T&&>>>;
239+
return has_value() ? Expected<U>(std::forward<F>(f)(std::get<0>(std::move(storage_))))
240+
: Expected<U>(std::move(error()));
241+
}
242+
222243
/**
223244
* Monadic error recovery: invoke @p f on the error, or pass the value through.
224245
*
@@ -235,6 +256,13 @@ class [[nodiscard]] Expected {
235256
return has_value() ? *this : std::forward<F>(f)(error());
236257
}
237258

259+
/** Rvalue overload of `or_else()`: passes the moved value through, or invokes @p f
260+
* with the moved-out error. */
261+
template <typename F>
262+
Expected or_else(F&& f) && {
263+
return has_value() ? std::move(*this) : std::forward<F>(f)(std::move(error()));
264+
}
265+
238266
private:
239267
std::variant<T, Error> storage_;
240268
};

0 commit comments

Comments
 (0)