137#ifndef CPP_RESULT_HAS_STATEMENT_EXPR
138#if defined(__GNUC__) || defined(__clang__)
139#define CPP_RESULT_HAS_STATEMENT_EXPR 1
141#define CPP_RESULT_HAS_STATEMENT_EXPR 0
145#ifndef CPP_RESULT_FEATURE_ALL
146#define CPP_RESULT_FEATURE_ALL 1
148#ifndef CPP_RESULT_FEATURE_UNWRAP
149#define CPP_RESULT_FEATURE_UNWRAP CPP_RESULT_FEATURE_ALL
151#ifndef CPP_RESULT_FEATURE_MAP
152#define CPP_RESULT_FEATURE_MAP CPP_RESULT_FEATURE_ALL
154#ifndef CPP_RESULT_FEATURE_ANDOR
155#define CPP_RESULT_FEATURE_ANDOR CPP_RESULT_FEATURE_ALL
157#ifndef CPP_RESULT_FEATURE_INSPECT
158#define CPP_RESULT_FEATURE_INSPECT CPP_RESULT_FEATURE_ALL
160#ifndef CPP_RESULT_FEATURE_CONTAINS
161#define CPP_RESULT_FEATURE_CONTAINS CPP_RESULT_FEATURE_ALL
163#ifndef CPP_RESULT_FEATURE_FLATTEN
164#define CPP_RESULT_FEATURE_FLATTEN CPP_RESULT_FEATURE_ALL
166#ifndef CPP_RESULT_FEATURE_OPTIONAL
167#define CPP_RESULT_FEATURE_OPTIONAL CPP_RESULT_FEATURE_ALL
190#if CPP_RESULT_HAS_STATEMENT_EXPR
193 auto &&__res = (expr); \
194 using __res_type = std::decay_t<decltype(__res)>; \
195 if (__res.is_err()) \
196 return __res_type::Err(__res.unwrap_err()); \
197 std::move(__res.unwrap()); \
201 ([&]() -> decltype(auto) { \
202 auto &&__res = (expr); \
203 using __res_type = std::decay_t<decltype(__res)>; \
204 if (__res.is_err()) \
205 return __res_type::Err(__res.unwrap_err()); \
206 return std::move(__res.unwrap()); \
229#define TRYL(name, expr) \
230 auto &&__res_##name = (expr); \
231 using __res_type_##name = std::decay_t<decltype(__res_##name)>; \
232 if (__res_##name.is_err()) \
233 return __res_type_##name::Err(__res_##name.unwrap_err()); \
234 auto &name = __res_##name.unwrap()
238#if CPP_RESULT_FEATURE_OPTIONAL
241#include <type_traits>
244#define EXPECT_OR_ABORT(cond, msg) \
247 std::fputs(msg, stderr); \
248 std::fputc('\n', stderr); \
268template <
typename T,
typename E>
class [[nodiscard]]
Result {
269 static_assert(!std::is_reference_v<T> && !std::is_reference_v<E>,
270 "Result<T,E> does not support reference types");
306 constexpr bool is_ok() const noexcept {
return is_ok_; }
315 constexpr bool is_err() const noexcept {
return !is_ok_; }
317#if CPP_RESULT_FEATURE_UNWRAP
330 inline const T &
unwrap() const noexcept {
361 return is_ok_ ? data_.value : default_value;
372 template <
typename F>
374 return is_ok_ ? data_.value : std::forward<F>(func)();
388 noexcept(std::is_nothrow_default_constructible_v<T>) {
405 const T &
expect(
const char *msg)
const noexcept {
435 template <
typename Pred>
437 noexcept(
noexcept(pred(std::declval<T>()))) {
438 return is_ok_ && pred(data_.value);
450 template <
typename Pred>
452 noexcept(
noexcept(pred(std::declval<E>()))) {
453 return !is_ok_ && pred(data_.error);
457#if CPP_RESULT_FEATURE_MAP
466 template <
typename F,
typename U = std::invoke_result_t<F, T>>
481 template <
typename F,
typename E2 = std::invoke_result_t<F, E>>
483 noexcept(
noexcept(func(std::declval<E>()))) {
496 template <
typename U,
typename F> U
map_or(U default_value, F &&func)
const {
497 return is_ok_ ? func(data_.value) : default_value;
509 template <
typename D,
typename F>
511 return is_ok_ ? func(data_.value) : default_fn();
515#if CPP_RESULT_FEATURE_ANDOR
526 template <
typename F,
typename R =
typename std::invoke_result_t<F, T>>
527 R
and_then(F &&func)
const noexcept(
noexcept(func(std::declval<T>()))) {
529 return func(data_.value);
530 return R::Err(data_.error);
541 template <
typename R2>
auto and_(R2 &&res)
const {
543 return std::forward<R2>(res);
555 template <
typename R2>
auto or_(R2 &&res)
const {
557 return std::forward<R2>(res);
568 template <
typename F>
auto or_else(F &&op)
const {
575#if CPP_RESULT_FEATURE_INSPECT
583 template <
typename F>
585 noexcept(
noexcept(func(std::declval<const T &>()))) {
598 template <
typename F>
600 noexcept(
noexcept(func(std::declval<const E &>()))) {
607#if CPP_RESULT_FEATURE_CONTAINS
615 bool contains(
const T &value)
const {
return is_ok_ && data_.value == value; }
625 return !is_ok_ && data_.error == error;
629#if CPP_RESULT_FEATURE_FLATTEN
639 using Inner =
decltype(data_.value);
642 return Inner::Err(data_.error);
646#if CPP_RESULT_FEATURE_OPTIONAL
655 std::optional<T>
ok()
const {
656 return is_ok_ ? std::optional<T>(data_.value) : std::nullopt;
667 std::optional<E>
err()
const {
668 return !is_ok_ ? std::optional<E>(data_.error) : std::nullopt;
675 Result(
Result &&other)
noexcept(std::is_nothrow_move_constructible_v<T> &&
676 std::is_nothrow_move_constructible_v<E>)
677 : is_ok_(other.is_ok_) {
679 new (&data_.value) T(std::move(other.data_.value));
681 new (&data_.error) E(std::move(other.data_.error));
686 std::is_nothrow_move_assignable_v<E>) {
687 if (
this != &other) {
689 is_ok_ = other.is_ok_;
691 new (&data_.value) T(std::move(other.data_.value));
693 new (&data_.error) E(std::move(other.data_.error));
700 std::is_nothrow_copy_constructible_v<T> &&
701 std::is_nothrow_copy_constructible_v<E>)
702 : is_ok_(other.is_ok_) {
704 new (&data_.value) T(other.data_.value);
706 new (&data_.error) E(other.data_.error);
710 std::is_nothrow_copy_assignable_v<T> &&
711 std::is_nothrow_copy_assignable_v<E>) {
712 if (
this != &other) {
714 is_ok_ = other.is_ok_;
716 new (&data_.value) T(other.data_.value);
718 new (&data_.error) E(other.data_.error);
732 explicit Result(T val) noexcept : is_ok_(
true) {
733 new (&data_.value) T(std::move(val));
736 explicit Result(E err) noexcept : is_ok_(
false) {
737 new (&data_.error) E(std::move(err));
740 void destroy() noexcept { is_ok_ ? data_.value.~T() : data_.error.~E(); }
758template <
typename E>
class [[nodiscard]]
Result<void, E> {
759 static_assert(!std::is_reference_v<E>,
760 "Result<void,E> does not support reference types");
789 inline bool is_ok() const noexcept {
return is_ok_; }
798 inline bool is_err() const noexcept {
return !is_ok_; }
836 template <
typename F,
typename U = std::invoke_result_t<F>>
851 template <
typename F,
typename E2 = std::invoke_result_t<F, E>>
853 noexcept(
noexcept(func(std::declval<E>()))) {
870 template <
typename F,
typename R = std::invoke_result_t<F>>
871 R
and_then(F &&func)
const noexcept(
noexcept(func())) {
874 return R::Err(error_);
910 template <
typename F>
924 template <
typename F>
926 noexcept(
noexcept(func(std::declval<const E &>()))) {
941 template <
typename Pred>
943 noexcept(
noexcept(pred(std::declval<E>()))) {
944 return !is_ok_ && pred(error_);
957 std::optional<E>
err()
const {
972 template <
typename R2>
auto and_(R2 &&res)
const {
974 return std::forward<R2>(res);
987 template <
typename R2>
auto or_(R2 &&res)
const {
989 return std::forward<R2>(res);
1001 template <
typename U,
typename F> U
map_or(U default_value, F &&func)
const {
1002 return is_ok_ ? func() : default_value;
1014 template <
typename D,
typename F>
1016 return is_ok_ ? func() : default_fn();
1026 bool contains_err(
const E &error)
const {
return !is_ok_ && error_ == error; }
1030 : is_ok_(other.is_ok_) {
1032 new (&error_) E(std::move(other.error_));
1037 if (
this != &other) {
1038 is_ok_ = other.is_ok_;
1040 new (&error_) E(std::move(other.error_));
1046 Result(
const Result &other)
noexcept(std::is_nothrow_copy_constructible_v<E>)
1047 : is_ok_(other.is_ok_) {
1049 new (&error_) E(other.error_);
1053 std::is_nothrow_copy_assignable_v<E>) {
1054 if (
this != &other) {
1055 is_ok_ = other.is_ok_;
1057 new (&error_) E(other.error_);
1066 Result() noexcept : is_ok_(true) {}
1067 explicit Result(E err) noexcept : is_ok_(
false) {
1068 new (&error_) E(std::move(err));
Result(const Result &other) noexcept(std::is_nothrow_copy_constructible_v< E >)
Definition result.hpp:1046
bool contains_err(const E &error) const
Returns true if the result is Err and contains the given error.
Definition result.hpp:1026
bool is_err() const noexcept
Returns true if the result is Err.
Definition result.hpp:798
const E & unwrap_err() const noexcept
Definition result.hpp:823
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_assignable_v< E >)
Definition result.hpp:1036
Result< U, E > map(F &&func) const noexcept(noexcept(func()))
Returns unit type if Ok, else returns error.
Definition result.hpp:837
bool is_err_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< E >())))
Returns true if the result is Err and the predicate returns true for the error.
Definition result.hpp:942
bool is_ok() const noexcept
Returns true if the result is Ok.
Definition result.hpp:789
auto and_(R2 &&res) const
Returns res if the result is Ok, otherwise returns self.
Definition result.hpp:972
E & expect_err(const char msg[]) noexcept
Unwraps the error or aborts with a custom message if Ok.
Definition result.hpp:893
Result(Result &&other) noexcept(std::is_nothrow_move_constructible_v< E >)
Definition result.hpp:1029
const E & expect_err(const char msg[]) const noexcept
Definition result.hpp:898
const Result & inspect_err(F &&func) const noexcept(noexcept(func(std::declval< const E & >())))
Calls func(error) if Err, returns self.
Definition result.hpp:925
R and_then(F &&func) const noexcept(noexcept(func()))
Chains another result-producing function if Ok, else propagates Err.
Definition result.hpp:871
U map_or(U default_value, F &&func) const
Applies a function if Ok, else returns default_value.
Definition result.hpp:1001
std::optional< E > err() const
Converts the Result into a std::optional<E> (Err value or std::nullopt).
Definition result.hpp:957
auto or_(R2 &&res) const
Returns res if the result is Err, otherwise returns self.
Definition result.hpp:987
const Result & inspect(F &&func) const noexcept(noexcept(func()))
Calls func() if Ok, returns self.
Definition result.hpp:911
static Result Ok() noexcept
Construct an Ok result.
Definition result.hpp:770
void unwrap() noexcept
Unwraps the value. Aborts if Err.
Definition result.hpp:807
auto map_or_else(D &&default_fn, F &&func) const
Applies a function if Ok, else computes a default with another function.
Definition result.hpp:1015
Result & operator=(const Result &other) noexcept(std::is_nothrow_copy_assignable_v< E >)
Definition result.hpp:1052
E & unwrap_err() noexcept
Unwraps the error. Aborts if Ok.
Definition result.hpp:819
Result< void, E2 > map_err(F &&func) const noexcept(noexcept(func(std::declval< E >())))
Maps the error if Err, else propagates Ok.
Definition result.hpp:852
void expect(const char msg[]) const noexcept
Unwraps the value or aborts with a custom message if Err.
Definition result.hpp:884
static Result Err(E err) noexcept
Construct an Err result.
Definition result.hpp:780
Result<T, E> - Holds either a value (Ok) or an error (Err).
Definition result.hpp:268
Result< T, E2 > map_err(F &&func) const noexcept(noexcept(func(std::declval< E >())))
Maps the error if Err, else propagates Ok.
Definition result.hpp:482
const E & expect_err(const char *msg) const noexcept
Definition result.hpp:421
T unwrap_or_default() const noexcept(std::is_nothrow_default_constructible_v< T >)
Returns the value if Ok, else returns a default-constructed value. Requires T to be default-construct...
Definition result.hpp:387
Result(const Result &other) noexcept(std::is_nothrow_copy_constructible_v< T > &&std::is_nothrow_copy_constructible_v< E >)
Definition result.hpp:699
auto map_or_else(D &&default_fn, F &&func) const
Applies a function to the value if Ok, else computes a default with another function.
Definition result.hpp:510
constexpr bool is_ok() const noexcept
Returns true if the result is Ok.
Definition result.hpp:306
T unwrap_or(T default_value) const noexcept
Returns value if Ok, else returns default_value.
Definition result.hpp:360
~Result()
Definition result.hpp:672
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_assignable_v< T > &&std::is_nothrow_move_assignable_v< E >)
Definition result.hpp:685
bool contains(const T &value) const
Returns true if the result is Ok and contains the given value.
Definition result.hpp:615
T & expect(const char *msg) noexcept
Unwraps the value or aborts with a custom message if Err.
Definition result.hpp:401
bool is_err_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< E >())))
Returns true if the result is Err and the predicate returns true for the error.
Definition result.hpp:451
auto and_(R2 &&res) const
Returns res if the result is Ok, otherwise returns self.
Definition result.hpp:541
auto or_else(F &&op) const
Calls op if the result is Err, otherwise returns self.
Definition result.hpp:568
auto flatten() const
Flattens a Result<Result<U, E>, E> into Result<U, E>.
Definition result.hpp:638
const Result & inspect(F &&func) const noexcept(noexcept(func(std::declval< const T & >())))
Calls func(value) if Ok, returns self.
Definition result.hpp:584
Result< U, E > map(F &&func) const noexcept(noexcept(func(std::declval< T >())))
Maps the value if Ok, else propagates Err.
Definition result.hpp:467
U map_or(U default_value, F &&func) const
Applies a function to the value if Ok, else returns default_value.
Definition result.hpp:496
const T & unwrap() const noexcept
Definition result.hpp:330
bool is_ok_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< T >())))
Returns true if the result is Ok and the predicate returns true for the value.
Definition result.hpp:436
const T & expect(const char *msg) const noexcept
Definition result.hpp:405
R and_then(F &&func) const noexcept(noexcept(func(std::declval< T >())))
Chains another result-producing function if Ok, else propagates Err.
Definition result.hpp:527
std::optional< T > ok() const
Returns the value as std::optional if Ok, otherwise std::nullopt.
Definition result.hpp:655
auto or_(R2 &&res) const
Returns res if the result is Err, otherwise returns self.
Definition result.hpp:555
Result & operator=(const Result &other) noexcept(std::is_nothrow_copy_assignable_v< T > &&std::is_nothrow_copy_assignable_v< E >)
Definition result.hpp:709
E & unwrap_err() noexcept
Unwraps the error. Aborts if Ok.
Definition result.hpp:343
T & unwrap() noexcept
Unwraps the value. Aborts if Err.
Definition result.hpp:326
Result(Result &&other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E >)
Definition result.hpp:675
T unwrap_or_else(F &&func) const noexcept(noexcept(func()))
Returns value if Ok, else calls func().
Definition result.hpp:373
const Result & inspect_err(F &&func) const noexcept(noexcept(func(std::declval< const E & >())))
Calls func(error) if Err, returns self.
Definition result.hpp:599
static Result Err(E err) noexcept
Construct an Err result.
Definition result.hpp:297
const E & unwrap_err() const noexcept
Definition result.hpp:347
static Result Ok(T val) noexcept
Construct an Ok result.
Definition result.hpp:284
bool contains_err(const E &error) const
Returns true if the result is Err and contains the given error.
Definition result.hpp:624
constexpr bool is_err() const noexcept
Returns true if the result is Err.
Definition result.hpp:315
E & expect_err(const char *msg) noexcept
Unwraps the error or aborts with a custom message if Ok.
Definition result.hpp:417
std::optional< E > err() const
Returns the error as std::optional if Err, otherwise std::nullopt.
Definition result.hpp:667
Definition result.hpp:253
Result< T, E > Err(E err)
Definition result.hpp:1075
Result< void, E > Ok()
Definition result.hpp:1078
#define EXPECT_OR_ABORT(cond, msg)
Definition result.hpp:244