template<typename T, typename StatusType>
class pw::Result< T, StatusType >
Error propagation primitive: value or error status.
The pw::Result<T, StatusType> class template is a union of a StatusType object (pw::Status by default) and an object of type T. Result<T, StatusType> models an object that is either a usable object, or an error status (of type StatusType) explaining why such an object is not present. It is typically the return value of a function which may fail.
To simplify its use in generic code and coroutines, Result is specialized for void.
Checking for success
Result<T, StatusType> can never hold an OK error status; instead, the presence of an object of type T indicates success (status().ok() == true). Use the Result<T, StatusType>::ok() member function to check for success.
Example:
result->DoSomethingCool();
} else {
PW_LOG_ERROR(
"Calculation failed: %s", result.
status().str());
}
constexpr bool ok() const
Definition: result.h:552
constexpr status_type status() const
Definition: result.h:559
Accessing objects
Accessing the object held by a Result<T, StatusType> should be performed via operator* or operator->, after a call to ok() confirms that the Result<T, StatusType> holds an object of type T:
Example:
Using Result<T, StatusType>::value() when no valid value is present will trigger a PW_ASSERT.
Example:
const Foo& foo = result.
value();
foo.DoSomethingCool();
constexpr const T & value() const &PW_ATTRIBUTE_LIFETIME_BOUND
Definition: result.h:609
Constructing result objects
A Result<T*> can be constructed from a null pointer like any other pointer value, and the result will be that ok() returns true and value() returns nullptr. Checking the value of a pointer in a Result<T*> generally requires a bit more care, to ensure both that a value is present and that value is not null:
PW_LOG_ERROR(
"Unable to look up the Foo: %s", result.
status().str());
} else if (*result == nullptr) {
PW_LOG_ERROR("Unexpected null pointer");
} else {
(*result)->DoSomethingCool();
}
Example factory implementation returning Result<T>:
if (arg <= 0) {
}
return Foo(arg);
}
static constexpr Status InvalidArgument()
Definition: status.h:175
<tt>Result<Status></tt> and <tt>Result<StatusType, StatusType></tt>
Prefer returning StatusType (or Result<void, StatusType> in generic code) instead of Result<StatusType, StatusType> when no additional value is needed. However, Result<StatusType, StatusType> is supported for generic code that wraps functions returning StatusType.
Because the value type and the status type are the same in Result<StatusType, StatusType>, constructing, assigning, or comparing with a StatusType (or StatusType::Code) always operates on the contained value (ok() == true), even if the provided status is not OK. To set an error status on a Result<StatusType, StatusType>, call reset(). To check or compare the status of the Result itself, use ok() or status().
- Example
constexpr void reset(status_type status)
Definition: result.h:564
static constexpr Status NotFound()
Definition: status.h:201
static constexpr Status Internal()
Definition: status.h:303
constexpr Status OkStatus()
Definition: status.h:431
@ PW_STATUS_INTERNAL
Definition: status.h:68
Source: pw_result/result_test.cc
- Template Parameters
-
| T | Type of the contained value (or void). |
| StatusType | Status type that represents the error. Defaults to pw::Status. Must be derived from pw::StatusBase and use an enum code. |
|
| template<typename S = StatusType, typename = std::enable_if_t<std::is_same_v<S, Status>>> |
| constexpr | Result () |
| |
| constexpr | Result (const Result &)=default |
| |
| constexpr Result & | operator= (const Result &)=default |
| |
| constexpr | Result (Result &&)=default |
| |
| constexpr Result & | operator= (Result &&)=default |
| |
| template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, const U & >, std::is_convertible< const U &, T >, std::negation< internal_result::IsConstructibleOrConvertibleFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr | Result (const Result< U, StatusType > &other) |
| |
|
template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, const U & >, std::negation< std::is_convertible< const U &, T > >, std::negation< internal_result::IsConstructibleOrConvertibleFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr | Result (const Result< U, StatusType > &other) |
| |
|
template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, U && >, std::is_convertible< U &&, T >, std::negation< internal_result::IsConstructibleOrConvertibleFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr | Result (Result< U, StatusType > &&other) |
| |
|
template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, U && >, std::negation< std::is_convertible< U &&, T > >, std::negation< internal_result::IsConstructibleOrConvertibleFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr | Result (Result< U, StatusType > &&other) |
| |
| template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, const U & >, std::is_assignable< T, const U & >, std::negation< internal_result::IsConstructibleOrConvertibleOrAssignableFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr Result & | operator= (const Result< U, StatusType > &other) |
| |
|
template<typename U , std::enable_if_t< std::conjunction< std::negation< std::is_same< T, U > >, std::is_constructible< T, U && >, std::is_assignable< T, U && >, std::negation< internal_result::IsConstructibleOrConvertibleOrAssignableFromResult< T, U, StatusType > > >::value, int > = 0> |
| constexpr Result & | operator= (Result< U, StatusType > &&other) |
| |
| template<typename U = status_type, std::enable_if_t< std::conjunction< std::negation< std::is_same< std::remove_cv_t< T >, status_type > >, std::is_convertible< U &&, status_type >, std::is_constructible< status_type, U && >, std::negation< std::is_same< std::decay_t< U >, Result< T, StatusType > > >, std::negation< std::is_same< std::decay_t< U >, std::remove_cv_t< T > > >, std::negation< std::is_same< std::decay_t< U >, std::in_place_t > >, std::negation< internal_result::HasConversionOperatorToResult< T, U &&, StatusType > > >::value, int > = 0> |
| constexpr | Result (U &&v) |
| |
|
template<typename U = status_type, std::enable_if_t< std::conjunction< std::negation< std::is_same< std::remove_cv_t< T >, status_type > >, std::negation< std::is_convertible< U &&, status_type > >, std::is_constructible< status_type, U && >, std::negation< std::is_same< std::decay_t< U >, Result< T, StatusType > > >, std::negation< std::is_same< std::decay_t< U >, std::remove_cv_t< T > > >, std::negation< std::is_same< std::decay_t< U >, std::in_place_t > >, std::negation< internal_result::HasConversionOperatorToResult< T, U &&, StatusType > > >::value, int > = 0> |
| constexpr | Result (U &&v) |
| |
| template<typename U = status_type, std::enable_if_t< std::conjunction< std::negation< std::is_same< std::remove_cv_t< T >, status_type > >, std::is_convertible< U &&, status_type >, std::is_constructible< status_type, U && >, std::negation< std::is_same< std::decay_t< U >, Result< T, StatusType > > >, std::negation< std::is_same< std::decay_t< U >, std::remove_cv_t< T > > >, std::negation< std::is_same< std::decay_t< U >, std::in_place_t > >, std::negation< internal_result::HasConversionOperatorToResult< T, U &&, StatusType > > >::value, int > = 0> |
| constexpr Result & | operator= (U &&v) |
| |
| template<typename U = T, typename = typename std::enable_if<std::conjunction< std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, std::disjunction< std::is_same<std::remove_cv_t<std::remove_reference_t<U>>, std::remove_cv_t<T>>, std::conjunction< std::disjunction< std::is_same<std::remove_cv_t<T>, status_type>, std::negation<std::is_convertible<U&&, status_type>>>, std::negation< internal_result:: HasConversionOperatorToResult<T, U&&, StatusType>>>>, internal_result::IsForwardingAssignmentValid<T, U&&, StatusType>>:: value>::type> |
| constexpr Result & | operator= (U &&v) |
| |
| template<typename... Args> |
| constexpr | Result (std::in_place_t, Args &&... args) |
| |
|
template<typename U , typename... Args> |
| constexpr | Result (std::in_place_t, std::initializer_list< U > ilist, Args &&... args) |
| |
| template<typename U = T, std::enable_if_t< std::conjunction< internal_result::IsDirectInitializationValid< T, U &&, StatusType >, std::is_constructible< T, U && >, std::is_convertible< U &&, T >, std::disjunction< std::is_same< std::remove_cv_t< std::remove_reference_t< U > >, std::remove_cv_t< T > >, std::conjunction< std::disjunction< std::is_same< std::remove_cv_t< T >, status_type >, std::negation< std::is_convertible< U &&, status_type > > >, std::negation< internal_result::HasConversionOperatorToResult< T, U &&, StatusType > > > > >::value, int > = 0> |
| constexpr | Result (U &&u) |
| |
|
template<typename U = T, std::enable_if_t< std::conjunction< internal_result::IsDirectInitializationValid< T, U &&, StatusType >, std::disjunction< std::is_same< std::remove_cv_t< std::remove_reference_t< U > >, std::remove_cv_t< T > >, std::conjunction< std::disjunction< std::is_same< std::remove_cv_t< T >, status_type >, std::negation< std::is_constructible< status_type, U && > > >, std::negation< internal_result::HasConversionOperatorToResult< T, U &&, StatusType > > > >, std::is_constructible< T, U && >, std::negation< std::is_convertible< U &&, T > > >::value, int > = 0> |
| constexpr | Result (U &&u) |
| |
| constexpr bool | ok () const |
| |
| constexpr status_type | status () const |
| |
| constexpr void | reset (status_type status) |
| |
| template<typename C , std::enable_if_t< std::is_same_v< C, typename status_type::Code >, int > = 0> |
| constexpr void | reset (C code) |
| |
| template<typename status_type::Code kCode> |
| constexpr void | reset () |
| |
| constexpr const T & | value () const &PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr T & | value () &PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr const T && | value () const &&PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr T && | value () &&PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr const T & | operator* () const &PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr T & | operator* () &PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr const T && | operator* () const &&PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr T && | operator* () &&PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr const T * | operator-> () const PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| constexpr T * | operator-> () PW_ATTRIBUTE_LIFETIME_BOUND |
| |
| template<typename U > |
| constexpr T | value_or (U &&default_value) const & |
| |
| template<typename U > |
| constexpr T | value_or (U &&default_value) && |
| |
| constexpr void | IgnoreError () const |
| |
| template<typename... Args> |
| constexpr T & | emplace (Args &&... args) |
| |
| template<typename U , typename... Args, std::enable_if_t< std::is_constructible< T, std::initializer_list< U > &, Args &&... >::value, int > = 0> |
| constexpr T & | emplace (std::initializer_list< U > ilist, Args &&... args) |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&>, std::enable_if_t< std::is_copy_constructible_v< Ret >, int > = 0> |
| constexpr Ret | and_then (Fn &&function) & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&&>, std::enable_if_t< std::is_move_constructible_v< Ret >, int > = 0> |
| constexpr Ret | and_then (Fn &&function) && |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const T&>, std::enable_if_t< std::is_copy_constructible_v< Ret >, int > = 0> |
| constexpr Ret | and_then (Fn &&function) const & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const T&&>, std::enable_if_t< std::is_move_constructible_v< Ret >, int > = 0> |
| constexpr Ret | and_then (Fn &&function) const && |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const status_type&>, std::enable_if_t<!std::is_void_v< Ret >, int > = 0> |
| constexpr Result< T, StatusType > | or_else (Fn &&function) const & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const status_type&>, std::enable_if_t< std::is_void_v< Ret >, int > = 0> |
| constexpr Result< T, StatusType > | or_else (Fn &&function) const & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, status_type&&>, std::enable_if_t<!std::is_void_v< Ret >, int > = 0> |
| constexpr Result< T, StatusType > | or_else (Fn &&function) && |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, status_type&&>, std::enable_if_t< std::is_void_v< Ret >, int > = 0> |
| constexpr Result< T, StatusType > | or_else (Fn &&function) && |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&>, std::enable_if_t< std::is_void_v< Ret >||std::is_copy_constructible_v< Ret >, int > = 0> |
| constexpr Result< Ret, StatusType > | transform (Fn &&function) & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&&>, std::enable_if_t< std::is_void_v< Ret >||std::is_move_constructible_v< Ret >, int > = 0> |
| constexpr Result< Ret, StatusType > | transform (Fn &&function) && |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const T&>, std::enable_if_t< std::is_void_v< Ret >||std::is_copy_constructible_v< Ret >, int > = 0> |
| constexpr Result< Ret, StatusType > | transform (Fn &&function) const & |
| |
| template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, const T&&>, std::enable_if_t< std::is_void_v< Ret >||std::is_move_constructible_v< Ret >, int > = 0> |
| constexpr Result< Ret, StatusType > | transform (Fn &&function) const && |
| |
|
|
template<typename U , typename S > |
| constexpr U && | internal::ConvertToValue (Result< U, S > &result) |
| |
| template<typename U = T, std::enable_if_t< internal_result::IsEqualityComparable< U, U >::value, int > = 0> |
| constexpr bool | operator== (const Result &lhs, const Result &rhs) |
| |
| template<typename U = T, std::enable_if_t< internal_result::IsEqualityComparable< U, U >::value, int > = 0> |
| constexpr bool | operator!= (const Result &lhs, const Result &rhs) |
| |
| template<typename U = T, std::enable_if_t<!std::is_same_v< std::remove_cv_t< U >, status_type >, int > = 0> |
| constexpr bool | operator== (const Result &lhs, status_type rhs) |
| |
| template<typename U = T, std::enable_if_t<!std::is_same_v< std::remove_cv_t< U >, status_type >, int > = 0> |
| constexpr bool | operator== (status_type lhs, const Result &rhs) |
| |
| template<typename U = T, std::enable_if_t<!std::is_same_v< std::remove_cv_t< U >, status_type >, int > = 0> |
| constexpr bool | operator!= (const Result &lhs, status_type rhs) |
| |
| template<typename U = T, std::enable_if_t<!std::is_same_v< std::remove_cv_t< U >, status_type >, int > = 0> |
| constexpr bool | operator!= (status_type lhs, const Result &rhs) |
| |
| template<typename U = T, std::enable_if_t< !std::is_same_v< std::remove_cv_t< U >, status_type > &&!std::is_same_v< std::remove_cv_t< U >, typename status_type::Code >, int > = 0> |
| constexpr bool | operator== (const Result &lhs, typename status_type::Code rhs) |
| |
| template<typename U = T, std::enable_if_t< !std::is_same_v< std::remove_cv_t< U >, status_type > &&!std::is_same_v< std::remove_cv_t< U >, typename status_type::Code >, int > = 0> |
| constexpr bool | operator== (typename status_type::Code lhs, const Result &rhs) |
| |
| template<typename U = T, std::enable_if_t< !std::is_same_v< std::remove_cv_t< U >, status_type > &&!std::is_same_v< std::remove_cv_t< U >, typename status_type::Code >, int > = 0> |
| constexpr bool | operator!= (const Result &lhs, typename status_type::Code rhs) |
| |
| template<typename U = T, std::enable_if_t< !std::is_same_v< std::remove_cv_t< U >, status_type > &&!std::is_same_v< std::remove_cv_t< U >, typename status_type::Code >, int > = 0> |
| constexpr bool | operator!= (typename status_type::Code lhs, const Result &rhs) |
| |
| template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0> |
| constexpr bool | operator== (const Result &lhs, const U &rhs) |
| |
| template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0> |
| constexpr bool | operator== (const U &lhs, const Result &rhs) |
| |
| template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0> |
| constexpr bool | operator!= (const Result &lhs, const U &rhs) |
| |
| template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0> |
| constexpr bool | operator!= (const U &lhs, const Result &rhs) |
| |