omni::expected
Defined in omni/Expected.h
-
template<typename TValue, typename TError>
class expected : public omni::detail::ExpectedImpl<TValue, TError> A monad which holds either an expected value (the success case) or an unexpected value (the error case).
Simple use of
expected
instances involve checking if an instancehas_value()
before accessing either thevalue()
orerror()
member.expected<int, string> foo(); int main() { auto ex = foo(); if (ex) std::cout << "Successfully got " << ex.value() << std::endl; else std::cout << "Error: " << ex.error() << std::endl; }
Advanced usage of
expected
involves using the monadic operations, which act on the stored value. This example is equivalent to the above:expected<int, string> foo(); int main() { foo() .transform([](int value) { std::cout << "Successfully got " << value << std::endl; }) .transform_error([](string const& err) { std::cout << "Error: " << err << std::endl; }); }
- Template Parameters
TValue – The type of expected value, returned in the success case.
TError – The type of unexpected value, returned in the error case.
Public Types
-
using error_type = TError
The type used in error cases. Unlike the C++23 definition of
std::expected
, this is allowed to bevoid
to match parity with other languages with result monads.
-
using unexpected_type = unexpected<error_type>
The
unexpected
type which contains this monad’s error_type.
-
template<typename UValue>
using rebind = expected<UValue, error_type> Get an
expected
type withUValue
as the value_type and the same error_type as this.
Public Functions
-
expected() = default
Create a valued instance through default construction.
This constructor is only enabled if value_type is default-constructable or
void
.This function is
noexcept
if value_type has anoexcept
default constructor or if it isvoid
.
-
expected(expected const &src) = default
Copy an expected instance from another. After this call,
this->has_value() == src.has_value()
and either thevalue
orerror
will have been constructed from the src instance.This operation is only enabled if both value_type and error_type are copy-constructible or
void
. This operation is trivial if both value_type and error_type have trivial copy constructors or arevoid
.This function is
noexcept
if both value_type and error_type havenoexcept
copy constructors or arevoid
.- Parameters
src – The source to copy from. It will remain unchanged by this operation.
-
expected(expected &&src) = default
Move an expected instance from another. After this call,
this->has_value() == src.has_value()
and either thevalue
orerror
will have been constructed fromstd::move(src).value()
orstd::move(src).error()
. Note that thehas_value
state is unchanged, but the src instance will be moved-from.This operation is only enabled if both value_type and error_type are move-constructible or
void
. This operation is trivial if both value_type and error_type have trivial move constructors or arevoid
.This function is
noexcept
if both value_type and error_type havenoexcept
move constructors or arevoid
.- Parameters
src – The source to move from. While the has_value state will remain unchanged, the active src instance will have been moved-from.
-
expected &operator=(expected const &src) = default
Copy-assign this instance from another. After this call,
this->has_value() == src.has_value()
.Assignment can happen in one of two ways. In the simple case,
this->has_value() == src.has_value()
before the call, so the copy assignment operator of the underlying type is used. Ifthis->has_value() != src.has_value()
before the call, then the active instance ofthis
gets the destructor called, then the other type is copy constructed (generally — see the “exceptions” section for more info). Note that this destruct-then-construct process happens even when value_type and error_type are the same.This operation is only enabled if both value_type and error_type are copy-assignable or
void
. This operation is trivial if both value_type and error_type have trivial copy assignment operators and trivial destructors or arevoid
.This function is
noexcept
if both value_type and error_type havenoexcept
copy constructors, copy assignment operators, andnoexcept
destructors or arevoid
.Note
On type-changing assignment with exceptions enabled, care is taken to ensure the contents of the monad are valid for use when exceptions are thrown. The “simple” destruct-then-construct process is only followed when copy construction of the type of the created instance is non-throwing. The exact algorithm used depends on the available
noexcept
operations (if any), but they involve a stack-based temporary and rollback. Note that a new instance might be constructed before the destruction of the old, so the ordering of these operations should not be relied on.- Parameters
src – The source to copy from. It will remain unchanged by this operation.
-
expected &operator=(expected &&src) = default
Move-assign this instance from another. After this call,
this->has_value() == src.has_value()
.Assignment can happen in one of two ways. In the simple case,
this->has_value() == src.has_value()
before the call, so the move assignment operator of the underlying type is used. Ifthis->has_value() != src.has_value()
before the call, then the active instance ofthis
gets the destructor called, then the other type is move constructed (generally — see the “exceptions” section for more info). Note that this destruct-then-construct process happens even when value_type and error_type are the same.This operation is only enabled if both value_type and error_type are move-assignable or
void
. This operation is trivial if both value_type and error_type have trivial move assignment operators and trivial destructors or arevoid
.This function is
noexcept
if both value_type and error_type havenoexcept
move constructors, move assignment operators, andnoexcept
destructors or arevoid
.Note
On type-changing assignment with exceptions enabled, care is taken to ensure the contents of the monad are valid for use when exceptions are thrown. The “simple” destruct-then-construct process is only followed when move construction of the type of the created instance is non-throwing. The exact algorithm used depends on the available
noexcept
operations (if any), but they involve a stack-based temporary and rollback. Note that a new instance might be constructed before the destruction of the old, so the ordering of these operations should not be relied on.- Parameters
src – The source to move from. While the has_value will remain unchanged, the active src instance will have been moved-from.
-
~expected() = default
Destroy this instance by calling the destructor of the active value.
This operation is trivial if both value_type and error_type are trivially destructible. This function is
noexcept
if both value_type and error_type havenoexcept
destructors.
-
template<typename UValue = TValue, std::enable_if_t<omni::detail::IsExpectedDirectConstructibleFrom<UValue, expected>::is_explicit, bool> = true>
inline explicit constexpr expected(UValue &&src) Construct an instance by forwarding src to construct the value_type by direct initialization. After this call,
this->has_value()
will be true.This constructor is only enabled when all of the following criteria is met:
value_type is constructible from
UValue
value_type is not
void
remove_cvref_t<UValue>
is notin_place_t
remove_cvref_t<UValue>
is notexpected<TValue, TError>
(the copy or move constructor is used instead)remove_cvref_t<UValue>
is not a specialization ofunexpected
if value_type is
bool
, thenUValue
can not be a specialization ofexpected
This constructor is
explicit
if conversion fromUValue
to value_type isexplicit
.
-
template<typename UValue, typename UError, std::enable_if_t<omni::detail::IsExpectedCopyConstructibleFrom<expected<UValue, UError>, expected>::is_explicit, bool> = true>
inline explicit constexpr expected(expected<UValue, UError> const &src) Convert from src by direct initialization from the active element. If
src.has_value()
, then this instance will have a value constructed fromsrc.value()
; otherwise, this instance will have an error constructed fromsrc.error()
. After this call,this->has_value() == src.has_value()
.This converting constructor is not
explicit
if conversion fromUValue
toTValue
andUError
toTError
are notexplicit
. Conversion fromvoid
tovoid
is also considered a nonexplicit
conversion. Stated differently, aUExpected
is implicitly convertible to aTExpected
if both of its components are implicitly convertible.Note
The rules for this are almost identical to
std::expected
, but they are expanded to supportvoid
as the error_type. Any case where the C++ Standard makes an exception when value_type isvoid
, that same exception has been extended to error_type ofvoid
.
-
template<typename UValue, typename UError, std::enable_if_t<omni::detail::IsExpectedMoveConstructibleFrom<expected<UValue, UError>, expected>::is_explicit, bool> = true>
inline explicit constexpr expected(expected<UValue, UError> &&src) Convert from src by direct initialization from the active element. If
src.has_value()
, then this instance will have a value constructed frommove(src).value()
; otherwise, this instance will have an error constructed frommove(src).error()
. After this call,this->has_value() == src.has_value()
. Note that the contents of src are moved-from, but not destructed, so the instances is still accessable.This converting constructor is not
explicit
if conversion fromUValue
toTValue
andUError
toTError
are notexplicit
. Conversion fromvoid
tovoid
is also considered a nonexplicit
conversion. Stated differently, aUExpected
is implicitly convertible to aTExpected
if both of its components are implicitly convertible.Note
The rules for this are almost identical to
std::expected
, but they are expanded to supportvoid
as the error_type. Any case where the C++ Standard makes an exception when value_type isvoid
, that same exception has been extended to error_type ofvoid
.
-
template<typename UError, std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError const&>, carb::cpp::negation<std::is_convertible<UError const&, TError>>>::value, bool> = true>
inline explicit constexpr expected(unexpected<UError> const &src) Construct an instance using src as the error value. The constructed instance
!this->has_value()
and thethis->error()
will have been constructed bysrc.error()
.This constructor is not
explicit
if the conversion from the sourceUError
toTError
is not explicit. Stated differently, anunexpected<UError>
is implicitly convertible to aexpected<TValue, TError>
(of arbitraryTValue
) ifUError
is implicitly convertible to aTError
.If
TError
isvoid
, thenUError
must also bevoid
to construct an instance.
-
template<typename UError, std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError&&>, carb::cpp::negation<std::is_convertible<UError&&, TError>>>::value, bool> = true>
inline explicit constexpr expected(unexpected<UError> &&src) Construct an instance using src as the error value. The constructed instance
!this->has_value()
and thethis->error()
will have been constructed bystd::move(src).error()
.This constructor is not
explicit
if the conversion from the sourceUError
toTError
is not explicit. Stated differently, anunexpected<UError>
is implicitly convertible to aexpected<TValue, TError>
(of arbitraryTValue
) ifUError
is implicitly convertible to aTError
.If
TError
isvoid
, thenUError
must also bevoid
to construct an instance.
-
inline constexpr bool has_value() const noexcept
Test if this instance has a
value
. If this returnstrue
, then a call tovalue()
will succeed, while a call toerror()
would not. If this returnsfalse
, a call toerror()
will succeed, while a call tovalue()
would not.
-
inline explicit constexpr operator bool() const noexcept
Test if this instance has a
value
. If this returnstrue
, then a call tovalue()
will succeed, while a call toerror()
would not. If this returnsfalse
, a call toerror()
will succeed, while a call tovalue()
would not.See also
-
constexpr value_type &value() &
If this instance
has_value()
, the value is returned by&
.If this instance does not have a value, this call will not succeed. If exceptions are enabled, then a
bad_expected_access
exception is thrown containing the copied contents oferror()
. If exceptions are disabled, then the program will terminate.Note
If value_type is
void
, the return type is exactlyvoid
instead ofvoid&
(which is illegal).
-
constexpr value_type const &value() const &
If this instance
has_value()
, the value is returned byconst&
.If this instance does not have a value, this call will not succeed. If exceptions are enabled, then a
bad_expected_access
exception is thrown containing the copied contents oferror()
. If exceptions are disabled, then the program will terminate.Note
If value_type is
void
, the return type is exactlyvoid
instead ofvoid const&
(which is illegal).
-
constexpr value_type &&value() &&
If this instance
has_value()
, the value is returned by&&
.If this instance does not have a value, this call will not succeed. If exceptions are enabled, then a
bad_expected_access
exception is thrown containing the moved contents oferror()
. If exceptions are disabled, then the program will terminate.Note
If value_type is
void
, the return type is exactlyvoid
instead ofvoid&&
(which is illegal).
-
constexpr value_type const &&value() const &&
If this instance
has_value()
, the value is returned byconst&&
.If this instance does not have a value, this call will not succeed. If exceptions are enabled, then a
bad_expected_access
exception is thrown containing the copied contents oferror()
. If exceptions are disabled, then the program will terminate.Note
If value_type is
void
, the return type is exactlyvoid
instead ofvoid const&&
(which is illegal).
-
template<typename UValue>
constexpr value_type value_or(UValue &&default_value) const & If this instance
has_value()
, the value is copied and returned; otherwise, a value_type instance is constructed from default_value.Note
If value_type is
void
, this member function does not exist. If value_type is not copy constructible, this will fail to compile in the immediate context (not SFINAE-safe).- Template Parameters
UValue – Must be convertible to value_type.
-
template<typename UValue>
constexpr value_type value_or(UValue &&default_value) && If this instance
has_value()
, the value is moved and returned; otherwise, a value_type instance is constructed from default_value.Note
If value_type is
void
, this member function does not exist. If value_type is not move constructible, this will fail to compile in the immediate context (not SFINAE-safe).- Template Parameters
UValue – Must be convertible to value_type.
-
constexpr error_type &error() & noexcept
If this instance
!has_value
(), the error is returned by&
.Note
If error_type is
void
, the return type is exactlyvoid
instead ofvoid&
(which is illegal).- Pre
!this->has_value()
: if this instance is not in the unexpected state, the program will terminate.
-
constexpr error_type const &error() const & noexcept
If this instance
!has_value
(), the error is returned byconst&
.Note
If error_type is
void
, the return type is exactlyvoid
instead ofvoid const&
(which is illegal).- Pre
!this->has_value()
: if this instance is not in the unexpected state, the program will terminate.
-
constexpr error_type &&error() && noexcept
If this instance
!has_value
(), the error is returned by&&
.Note
If error_type is
void
, the return type is exactlyvoid
instead ofvoid&&
(which is illegal).- Pre
!this->has_value()
: if this instance is not in the unexpected state, the program will terminate.
-
constexpr error_type const &&error() const && noexcept
If this instance
!has_value
(), the error is returned byconst&&
.Note
If error_type is
void
, the return type is exactlyvoid
instead ofvoid const&&
(which is illegal).- Pre
!this->has_value()
: if this instance is not in the unexpected state, the program will terminate.
-
constexpr value_type *operator->() noexcept
Access the underlying value instance. If
has_value()
isfalse
, the program will terminate.This function is only available if value_type is not
void
.
-
constexpr value_type const *operator->() const noexcept
Access the underlying value instance. If
has_value()
isfalse
, the program will terminate.This function is only available if value_type is not
void
.
-
constexpr value_type &operator*() & noexcept
If this instance
has_value()
, the value is returned by&
.If this instance does not have a value, the program will terminate.
Note
If value_type is
void
, this overload is not enabled (only theconst&
is accessible).
-
constexpr value_type const &operator*() const & noexcept
If this instance
has_value()
, the value is returned byconst&
.If this instance does not have a value, the program will terminate.
Note
If value_type is
void
, the return type is exactlyvoid
instead ofvoid const&
(which is illegal).
-
constexpr value_type &&operator*() && noexcept
If this instance
has_value()
, the value is returned by&&
.If this instance does not have a value, the program will terminate.
Note
If value_type is
void
, this overload is not enabled (only theconst&
is accessible).
-
constexpr value_type const &&operator*() const && noexcept
If this instance
has_value()
, the value is returned byconst&&
.If this instance does not have a value, the program will terminate.
Note
If value_type is
void
, this overload is not enabled (only theconst&
is accessible).
-
template<typename ...TArgs>
value_type &emplace(TArgs&&... args) noexcept Destroy the current contents of this instance and construct the value_type of this instance through direct-initialization.
If value_type is not
void
, this function accepts two overloads:template <typename... TArgs> value_type& emplace(TArgs&&... args) noexcept
(only enabled ifstd::is_nothrow_constructible<value_type, TArgs...>::value
istrue
)template <typename U, typename... TArgs> value_type& emplace(std::initializer_list<U>& il, TArgs&&... args) noexcept
(only enabled ifstd::is_nothrow_constructible<value_type, std::initializer_list<U>&, TArgs...>::value
istrue
)
After calling this function,
has_value()
will returntrue
.
-
void emplace() noexcept
If value_type is
void
, thenemplace
is a no argument function that returnsvoid
.After calling this function,
has_value()
will returntrue
.
-
template<typename F>
inline constexpr auto transform(F &&f) const & Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureUValue (value_type const&)
; if value_type isvoid
,F
has the signatureUValue ()
.- Returns
An
expected<UValue, error_type>
, where the returned value has been transformed by f. The value_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform(F &&f) & Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureUValue (value_type&)
; if value_type isvoid
,F
has the signatureUValue ()
.- Returns
An
expected<UValue, error_type>
, where the returned value has been transformed by f. The value_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform(F &&f) && Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureUValue (value_type&&)
; if value_type isvoid
,F
has the signatureUValue ()
.- Returns
An
expected<UValue, error_type>
, where the returned value has been transformed by f. The value_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform(F &&f) const && Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureUValue (value_type const&&)
; if value_type isvoid
,F
has the signatureUValue ()
.- Returns
An
expected<UValue, error_type>
, where the returned value has been transformed by f. The value_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto and_then(F &&f) const & Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureexpected<UValue, UError> (value_type const&)
; if value_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UError
must be constructible from error_type orvoid
.
-
template<typename F>
inline constexpr auto and_then(F &&f) & Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureexpected<UValue, UError> (value_type&)
; if value_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UError
must be constructible from error_type orvoid
.
-
template<typename F>
inline constexpr auto and_then(F &&f) && Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureexpected<UValue, UError> (value_type&&)
; if value_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UError
must be constructible from error_type orvoid
.
-
template<typename F>
inline constexpr auto and_then(F &&f) const && Transform the value by f if this
has_value()
or return the error if it does not.- Template Parameters
F – If value_type is not
void
,F
has the signatureexpected<UValue, UError> (value_type const&&)
; if value_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UError
must be constructible from error_type orvoid
.
-
template<typename F>
inline constexpr auto transform_error(F &&f) const & Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureUError (error_type const&)
; if error_type isvoid
,F
has the signatureUError ()
.- Returns
An
expected<value_type, UError>
, where the returned error has been transformed by f. The error_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform_error(F &&f) & Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureUError (error_type&)
; if error_type isvoid
,F
has the signatureUError ()
.- Returns
An
expected<value_type, UError>
, where the returned error has been transformed by f. The error_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform_error(F &&f) && Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureUError (error_type&&)
; if error_type isvoid
,F
has the signatureUError ()
.- Returns
An
expected<value_type, UError>
, where the returned error has been transformed by f. The error_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto transform_error(F &&f) const && Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureUError (error_type const&&)
; if error_type isvoid
,F
has the signatureUError ()
.- Returns
An
expected<value_type, UError>
, where the returned error has been transformed by f. The error_type of the returned instance is the result type ofF
.
-
template<typename F>
inline constexpr auto or_else(F &&f) const & Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureexpected<UValue, UError> (error_type const&)
; if error_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UValue
must be constructible from value_type orvoid
.
-
template<typename F>
inline constexpr auto or_else(F &&f) & Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureexpected<UValue, UError> (error_type&)
; if error_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UValue
must be constructible from value_type orvoid
.
-
template<typename F>
inline constexpr auto or_else(F &&f) && Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureexpected<UValue, UError> (error_type&&)
; if error_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UValue
must be constructible from value_type orvoid
.
-
template<typename F>
inline constexpr auto or_else(F &&f) const && Transform the error by f if this
has_value()
isfalse
or return the value if it does not.- Template Parameters
F – If error_type is not
void
,F
has the signatureexpected<UValue, UError> (error_type const&&)
; if error_type isvoid
,F
has the signatureexpected<UValue, UError> ()
. In both cases,UValue
must be constructible from value_type orvoid
.