basic_outcome<T, EC, EP, NoValuePolicy>
A type carrying one of (i) a successful T
(ii) a disappointment EC
(iii) a failure EP
(iv) both a disappointment EC
and a failure EP
, with NoValuePolicy
specifying what to do if one tries to read state which isn’t there, and enabling injection of hooks to trap when lifecycle events occur. Any one, two, or all of T
, EC
and EP
can be void
to indicate no value for that state is present. Detectable using is_basic_outcome<T>
.
Requires: Concept requirements if C++ 20, else static asserted:
- That trait
type_can_be_used_in_basic_result<R>
is true forT
,EC
andEP
. - That either
EC
isvoid
orDefaultConstructible
(Outcome v2.1 and earlier only). - That either
EP
isvoid
orDefaultConstructible
.
Namespace: OUTCOME_V2_NAMESPACE
Header: <outcome/basic_outcome.hpp>
Inclusions: The very lightest weight of C and C++ header files:
<cstdint>
<initializer_list>
<iosfwd>
<new>
<type_traits>
- If
OUTCOME_USE_STD_IN_PLACE_TYPE
is1
,<utility>
(defaults to1
for C++ 17 or later only) - If C++ exceptions disabled and
OUTCOME_DISABLE_EXECINFO
undefined only (used to print stack backtraces on “exception throw”):<sal.h>
(Windows only)<stddef.h>
(Windows only)<string.h>
(Windows only)<execinfo.h>
(POSIX only)
<cstdio>
<cstdlib>
<cassert>
This very light weight set of inclusion dependencies makes basic outcome suitable for use in global header files of very large C++ codebases.
Design rationale
basic_outcome
extends basic_result<T, E, NoValuePolicy>
with a third state to transport,
conventionally (but not necessarily) some sort of “abort” or “exceptional” state which a function can
return to indicate that not only did the operation fail, but it did so catastrophically i.e. please
abort any attempt to retry the operation.
A perfect alternative is to throw a C++ exception for the abort code path, and indeed most programs
ought to do exactly that instead of using basic_outcome
. However there are a number of use cases
where choosing basic_outcome
shines:
- Where C++ exceptions or RTTI is not available, but the ability to fail catastrophically without terminating the program is important.
- Where deterministic behaviour is required even in the catastrophic failure situation.
- In unit test suites of code using Outcome it is extremely convenient to accumulate test failures
into a
basic_outcome
for later reporting. A similar convenience applies to RPC situations, where C++ exception throws need to be accumulated for reporting back to the initiating endpoint. - Where a function is “dual use deterministic” i.e. it can be used deterministically, in which case
one switches control flow based on
.error()
, or it can be used non-deterministically by throwing an exception perhaps carrying a custom payload.
Public member type aliases
value_type
isT
.error_type
isEC
.exception_type
isEP
.no_value_policy_type
isNoValuePolicy
.value_type_if_enabled
isT
if construction fromT
is available, else it is a usefully named unusable internal type.error_type_if_enabled
isEC
if construction fromEC
is available, else it is a usefully named unusable internal type.exception_type_if_enabled
isEP
if construction fromEP
is available, else it is a usefully named unusable internal type.rebind<A, B = EC, C = EP, D = NoValuePolicy>
isbasic_outcome<A, B, C, D>
.
Protected member predicate booleans
predicate::constructors_enabled
is constexpr boolean true if:- Decayed
value_type
and decayederror_type
are not the same type, or both arevoid
. - Decayed
value_type
and decayedexception_type
are not the same type, or both arevoid
. - Decayed
error_type
and decayedexception_type
are not the same type, or both arevoid
.
- Decayed
predicate::implicit_constructors_enabled
is constexpr boolean true if:predicate::constructors_enabled
is true.- Trait
is_error_type<E>
is not true for both decayedvalue_type
and decayederror_type
at the same time. value_type
is not implicitly constructible fromerror_type
anderror_type
is not implicitly constructible fromvalue_type
.
OR
traitis_error_type<E>
is true for decayederror_type
anderror_type
is not implicitly constructible fromvalue_type
andvalue_type
is an integral type.value_type
is not implicitly constructible fromexception_type
.error_type
is not implicitly constructible fromexception_type
.exception_type
is not implicitly constructible fromvalue_type
.exception_type
is not implicitly constructible fromerror_type
.
predicate::enable_value_converting_constructor<A>
is constexpr boolean true if:predicate::constructors_enabled
is true.- Decayed
A
is not thisbasic_outcome
type. predicate::implicit_constructors_enabled
is true.- Decayed
A
is not anin_place_type_t
. - Trait
is_error_type_enum<E, Enum>
is false forerror_type
and decayedA
. value_type
is implicitly constructible fromA
anderror_type
is not implicitly constructible fromA
.
ORvalue_type
is the exact same type as decayedA
andvalue_type
is implicitly constructible fromA
.exception_type
is not implicitly constructible fromA
.
predicate::enable_error_converting_constructor<A>
is constexpr boolean true if:predicate::constructors_enabled
is true.- Decayed
A
is not thisbasic_outcome
type. predicate::implicit_constructors_enabled
is true.- Decayed
A
is not anin_place_type_t
. - Trait
is_error_type_enum<E, Enum>
is false forerror_type
and decayedA
. value_type
is not implicitly constructible fromA
anderror_type
is implicitly constructible fromA
.
ORerror_type
is the exact same type as decayedA
anderror_type
is implicitly constructible fromA
.exception_type
is not implicitly constructible fromA
.
predicate::enable_error_condition_converting_constructor<ErrorCondEnum>
is constexpr boolean true if:predicate::constructors_enabled
is true.- Decayed
ErrorCondEnum
is not thisbasic_outcome
type. - Decayed
ErrorCondEnum
is not anin_place_type_t
. - Trait
is_error_type_enum<E, Enum>
is true forerror_type
and decayedErrorCondEnum
. exception_type
is not implicitly constructible fromErrorCondEnum
.
predicate::enable_exception_converting_constructor<A>
is constexpr boolean true if:predicate::constructors_enabled
is true.- Decayed
A
is not thisbasic_outcome
type. predicate::implicit_constructors_enabled
is true.- Decayed
A
is not anin_place_type_t
. value_type
is not implicitly constructible fromA
.error_type
is not implicitly constructible fromA
.exception_type
is implicitly constructible fromA
.
predicate::enable_error_exception_converting_constructor<A, B>
is constexpr boolean true if:predicate::constructors_enabled
is true.- Decayed
A
is not thisbasic_outcome
type. predicate::implicit_constructors_enabled
is true.- Decayed
A
is not anin_place_type_t
. value_type
is not implicitly constructible fromA
.error_type
is implicitly constructible fromA
.value_type
is not implicitly constructible fromB
.exception_type
is implicitly constructible fromB
.
predicate::enable_compatible_conversion<A, B, C, D>
is constexpr boolean true if:predicate::constructors_enabled
is true.basic_outcome<A, B, C, D>
is not thisbasic_outcome
type.A
isvoid
ORvalue_type
is explicitly constructible fromA
.B
isvoid
ORerror_type
is explicitly constructible fromB
.C
isvoid
ORexception_type
is explicitly constructible fromC
.
predicate::enable_make_error_code_compatible_conversion<A, B, C, D>
is constexpr boolean true if:predicate::constructors_enabled
is true.basic_outcome<A, B, C, D>
is not thisbasic_outcome
type.- Trait
is_error_code_available<T>
is true for decayederror_type
. predicate::enable_compatible_conversion<A, B, C, D>
is not true.A
isvoid
ORvalue_type
is explicitly constructible fromA
.error_type
is explicitly constructible frommake_error_code(B)
.C
isvoid
ORexception_type
is explicitly constructible fromC
.
predicate::enable_inplace_value_constructor<Args...>
is constexpr boolean true if:predicate::constructors_enabled
is true.value_type
isvoid
ORvalue_type
is explicitly constructible fromArgs...
.
predicate::enable_inplace_error_constructor<Args...>
is constexpr boolean true if:predicate::constructors_enabled
is true.error_type
isvoid
ORerror_type
is explicitly constructible fromArgs...
.
predicate::enable_inplace_exception_constructor<Args...>
is constexpr boolean true if:predicate::constructors_enabled
is true.exception_type
isvoid
ORexception_type
is explicitly constructible fromArgs...
.
predicate::enable_inplace_value_error_exception_constructor<Args...>
is constexpr boolean true if:predicate::constructors_enabled
is true.predicate::implicit_constructors_enabled
is true.- Exactly one of
value_type
is explicitly constructible fromArgs...
, orerror_type
is explicitly constructible fromArgs...
, orexception_type
is explicitly constructible fromArgs...
.
Summary of standard requirements provided
, always deleted to force user to choose valued or errored or excepted for every outcome instanced.DefaultConstructible
MoveConstructible
, if all ofvalue_type
,error_type
andexception_type
implement move constructors.CopyConstructible
, if all ofvalue_type
,error_type
andexception_type
implement copy constructors.MoveAssignable
, if all ofvalue_type
,error_type
andexception_type
implement move constructors and move assignment.CopyAssignable
, if all ofvalue_type
,error_type
andexception_type
implement copy constructors and copy assignment.Destructible
.Swappable
, with the strong rather than weak guarantee. Seevoid swap(basic_outcome &)
for more information.TriviallyCopyable
, if all ofvalue_type
,error_type
andexception_type
are trivially copyable.TrivialType
, if all ofvalue_type
,error_type
andexception_type
are trivial types.LiteralType
, if all ofvalue_type
,error_type
andexception_type
are literal types.. It is implementation defined ifStandardLayoutType
basic_outcome
can be used by C. However all of the three major compilers MSVC, GCC and clang implement C layout ofbasic_outcome
as follows:struct outcome_layout { struct trivially_copyable_result_layout { union { value_type value; error_type error; }; unsigned int flags; }; exception_type exception; };
… if both
value_type
anderror_type
areTriviallyCopyable
, otherwise:struct outcome_layout { struct non_trivially_copyable_result_layout { value_type value; unsigned int flags; error_type error; }; exception_type exception; };
If you choose standard layout
value_type
,error_type
andexception_type
,basic_outcome
works fine from C on MSVC, GCC and clang.EqualityComparable
, if all ofvalue_type
,error_type
andexception_type
implement equality comparisons with one another., not implemented due to availability of implicit conversions fromLessThanComparable
value_type
,error_type
andexception_type
, this can cause major surprise (i.e. hard to diagnose bugs), so we don’t implement these at all., not implemented as a generic implementation of a unique hash for non-valued items which are unequal would require a dependency on RTTI being enabled.Hash
Thus basic_outcome
meets the Regular
concept if all of value_type
, error_type
and exception_type
are Regular
, except for the lack of a default constructor. Often where one needs a default constructor, wrapping basic_outcome
into
std::optional<T>
will suffice.
Public member functions
Disabling constructors
-
basic_outcome(Args...) = delete
Disabling catchall constructor used to give useful diagnostic error when trying to use non-inplace constructors when
predicate::constructors_enabled
is false. -
basic_outcome(X &&) = delete
Disabling implicit constructor used to give useful diagnostic error when trying to use implicit constructors when
predicate::implicit_constructors_enabled
is false.
Copy and move constructors and assignment, and destructor
-
basic_outcome() = delete
The default constructor (disabled).
-
basic_outcome(basic_outcome &&)
Move constructor. Constexpr, triviality and noexcept propagating.
-
basic_outcome(const basic_outcome &)
Copy constructor. Constexpr, triviality and noexcept propagating.
-
basic_outcome &operator=(basic_outcome &&)
Move assignment. Constexpr, triviality and noexcept propagating.
-
basic_outcome &operator=(const basic_outcome &)
Copy assignment. Constexpr, triviality and noexcept propagating.
-
~basic_outcome()
Destructor. Constexpr, triviality and noexcept propagating.
Converting constructors
-
basic_outcome(R &&)
Implicit
value_type
constructor. Available ifpredicate::enable_value_converting_constructor<R>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(S &&)
Implicit
error_type
constructor. Available ifpredicate::enable_error_converting_constructor<S>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(ErrorCondEnum &&)
Implicit
error_type
fromErrorCondEnum
constructor. Available ifpredicate::enable_error_condition_converting_constructor<ErrorCondEnum>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(P &&)
Implicit
exception_type
constructor. Available ifpredicate::enable_exception_converting_constructor<P>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(S &&, P &&)
Implicit
error_type
+exception_type
constructor. Available ifpredicate::enable_error_exception_converting_constructor<S, P>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(concepts::value_or_error<T, E> &&)
Explicit converting constructor from
concepts::value_or_error<T, E>
concept matching types. Available ifconvert::value_or_error<>
permits it. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(const basic_outcome<A, B, C, D> &)
Explicit converting copy constructor from compatible
basic_outcome
. Available ifpredicate::enable_compatible_conversion<A, B, C, D>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(basic_outcome<A, B, C, D> &&)
Explicit converting move constructor from compatible
basic_outcome
. Available ifpredicate::enable_compatible_conversion<A, B, C, D>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(const basic_result<A, B, C> &)
Explicit converting copy constructor from compatible
basic_result
. Available ifpredicate::enable_compatible_conversion<A, B, void, C>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(basic_result<A, B, C> &&)
Explicit converting move constructor from compatible
basic_result
. Available ifpredicate::enable_compatible_conversion<A, B, void, C>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(const basic_result<A, B, C> &)
Explicit converting copy constructor from compatible
basic_result
. Available ifpredicate::enable_make_error_code_compatible_conversion<A, B, void, C>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(basic_result<A, B, C> &&)
Explicit converting move constructor from compatible
basic_result
. Available ifpredicate::enable_make_error_code_compatible_conversion<A, B, void, C>
is true. Constexpr, triviality and noexcept propagating.
Inplace constructors
-
explicit basic_outcome(in_place_type_t<value_type_if_enabled>, Args ...)
Explicit inplace value constructor. Available if
predicate::enable_inplace_value_constructor<Args ...>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(in_place_type_t<value_type_if_enabled>, std::initializer_list<U>, Args ...)
Explicit inplace value constructor. Available if
predicate::enable_inplace_value_constructor<std::initializer_list<U>, Args ...>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(in_place_type_t<error_type_if_enabled>, Args ...)
Explicit inplace error constructor. Available if
predicate::enable_inplace_error_constructor<Args ...>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(in_place_type_t<error_type_if_enabled>, std::initializer_list<U>, Args ...)
Explicit inplace error constructor. Available if
predicate::enable_inplace_error_constructor<std::initializer_list<U>, Args ...>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(in_place_type_t<exception_type_if_enabled>, Args ...)
Explicit inplace exception constructor. Available if
predicate::enable_inplace_exception_constructor<Args ...>
is true. Constexpr, triviality and noexcept propagating. -
explicit basic_outcome(in_place_type_t<exception_type_if_enabled>, std::initializer_list<U>, Args ...)
Explicit inplace exception constructor. Available if
predicate::enable_inplace_exception_constructor<std::initializer_list<U>, Args ...>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(A1 &&, A2 &&, Args ...)
Implicit inplace value or error or exception constructor. Available if
predicate::enable_inplace_value_error_exception_constructor<A1, A2, Args ...>
is true. Constexpr, triviality and noexcept propagating.
Tagged constructors
-
basic_outcome(const success_type<T> &)
Implicit value-from-success-type-sugar copy constructor. Available if
predicate::enable_compatible_conversion<T, void, void>
is true, orT
isvoid
. Constexpr, triviality and noexcept propagating. -
basic_outcome(success_type<T> &&)
Implicit value-from-success-type-sugar move constructor. Available if
predicate::enable_compatible_conversion<T, void, void>
is true, orT
isvoid
. Constexpr, triviality and noexcept propagating. -
basic_outcome(const failure_type<EC> &)
Implicit error-from-failure-type-sugar copy constructor. Available if
predicate::enable_compatible_conversion<void, EC, void, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(failure_type<EC> &&)
Implicit error-from-failure-type-sugar move constructor. Available if
predicate::enable_compatible_conversion<void, EC, void, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(const failure_type<EC> &)
Implicit error-from-failure-type-sugar copy constructor. Available if
predicate::enable_make_error_code_compatible_conversion<void, EC, void, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(failure_type<EC> &&)
Implicit error-from-failure-type-sugar move constructor. Available if
predicate::enable_make_error_code_compatible_conversion<void, EC, void, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(const failure_type<EP> &)
Implicit exception-from-failure-type-sugar copy constructor. Available if
predicate::enable_compatible_conversion<void, void, EP, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(failure_type<EP> &&)
Implicit exception-from-failure-type-sugar move constructor. Available if
predicate::enable_compatible_conversion<void, void, EP, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(const failure_type<EC, EP> &)
Implicit error-and-exception-from-failure-type-sugar copy constructor. Available if
predicate::enable_compatible_conversion<void, EC, EP, void>
is true. Constexpr, triviality and noexcept propagating. -
basic_outcome(failure_type<EC, EP> &&)
Implicit error-and-exception-from-failure-type-sugar move constructor. Available if
predicate::enable_compatible_conversion<void, EC, EP, void>
is true. Constexpr, triviality and noexcept propagating.
Observers
-
explicit operator bool() const noexcept
Returns true if a value is present. Constexpr, never throws.
-
bool has_value() const noexcept
Returns true if a value is present. Constexpr, never throws.
-
bool has_error() const noexcept
Returns true if an error is present. Constexpr, never throws.
-
bool has_exception() const noexcept
Returns true if an exception is present. Constexpr, never throws.
-
bool has_failure() const noexcept
Returns true if there is either an error or an exception. Constexpr, never throws.
-
value_type &assume_value() & noexcept
Narrow contract lvalue reference observer of any value present. Constexpr propagating, never throws.
-
const value_type &assume_value() const & noexcept
Narrow contract const lvalue reference observer of any value present. Constexpr propagating, never throws.
-
value_type &&assume_value() && noexcept
Narrow contract rvalue reference observer of any value present. Constexpr propagating, never throws.
-
const value_type &&assume_value() const && noexcept
Narrow contract const rvalue reference observer of any value present. Constexpr propagating, never throws.
-
value_type &value() &
Wide contract lvalue reference observer of any value present. Constexpr propagating.
-
const value_type &value() const &
Wide contract const lvalue reference observer of any value present. Constexpr propagating.
-
value_type &&value() &&
Wide contract rvalue reference observer of any value present. Constexpr propagating.
-
const value_type &&value() const &&
Wide contract const rvalue reference observer of any value present. Constexpr propagating.
-
error_type &assume_error() & noexcept
Narrow contract lvalue reference observer of the stored error. Constexpr propagating, never throws.
-
const error_type &assume_error() const & noexcept
Narrow contract const lvalue reference observer of the stored error. Constexpr propagating, never throws.
-
error_type &&assume_error() && noexcept
Narrow contract rvalue reference observer of the stored error. Constexpr propagating, never throws.
-
const error_type &&assume_error() const && noexcept
Narrow contract const rvalue reference observer of the stored error. Constexpr propagating, never throws.
-
error_type &error() &
Wide contract lvalue reference observer of the stored error. Constexpr propagating.
-
const error_type &error() const &
Wide contract const lvalue reference observer of the stored error. Constexpr propagating.
-
error_type &&error() &&
Wide contract rvalue reference observer of the stored error. Constexpr propagating.
-
const error_type &&error() const &&
Wide contract const rvalue reference observer of the stored error. Constexpr propagating.
-
exception_type &assume_exception() & noexcept
Narrow contract lvalue reference observer of the stored exception. Constexpr propagating, never throws.
-
const exception_type &assume_exception() const & noexcept
Narrow contract const lvalue reference observer of the stored exception. Constexpr propagating, never throws.
-
const exception_type &&assume_exception() const && noexcept
Narrow contract const rvalue reference observer of the stored exception. Constexpr propagating, never throws.
-
exception_type &&assume_exception() && noexcept
Narrow contract rvalue reference observer of the stored exception. Constexpr propagating, never throws.
-
exception_type &exception() &
Wide contract lvalue reference observer of the stored exception. Constexpr propagating.
-
const exception_type &exception() const &
Wide contract const lvalue reference observer of the stored exception. Constexpr propagating.
-
exception_type &&exception() &&
Wide contract rvalue reference observer of the stored exception. Constexpr propagating.
-
const exception_type &&exception() const &&
Wide contract const rvalue reference observer of the stored exception. Constexpr propagating.
-
exception_type failure() const noexcept
Synthesising observer of the stored exception or error. Available if the traits
is_error_code_available<T>
andis_exception_ptr_available<T>
are both true. Never throws. -
failure_type<error_type, exception_type> as_failure() const &
Return the output from free function
failure()
containing a copy of any errored and/or excepted state.
Modifiers
-
void swap(basic_outcome &)
Swap one basic_outcome with another, with the strong guarantee. Noexcept propagating.
-
failure_type<error_type, exception_type> as_failure() &&
Return the output from free function
failure()
containing a move of any errored and/or excepted state.
Comparisons
See above for why LessThanComparable
is not implemented.
-
bool operator==(const basic_result<A, B, C> &) const
Returns true if this outcome compares equal to the other result. Constexpr and noexcept propagating.
-
bool operator==(const basic_outcome<A, B, C, D> &) const
Returns true if this outcome compares equal to the other outcome. Constexpr and noexcept propagating.
-
bool operator==(const success_type<A> &) const
Returns true if this result compares equal to the success type sugar. Constexpr and noexcept propagating.
-
bool operator==(const failure_type<A, B> &) const
Returns true if this outcome compares equal to the failure type sugar. Constexpr and noexcept propagating.
-
bool operator!=(const basic_result<A, B, C> &) const
Returns true if this outcome does not compare equal to the other result. Constexpr and noexcept propagating.
-
bool operator!=(const basic_outcome<A, B, C, D> &) const
Returns true if this outcome does not compare equal to the other outcome. Constexpr and noexcept propagating.
-
bool operator!=(const success_type<A> &) const
Returns true if this outcome does not compare equal to the success type sugar. Constexpr and noexcept propagating.
-
bool operator!=(const failure_type<A, B> &) const
Returns true if this outcome does not compare equal to the failure type sugar. Constexpr and noexcept propagating.