Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. C/C++
  4. pw_result
  5. pw::Result< T, StatusType > Class Template Reference
Loading...
Searching...
No Matches
pw::Result< T, StatusType > Class Template Referencefinal

Overview

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<Foo> result = DoBigCalculationThatCouldFail();
if (result.ok()) {
result->DoSomethingCool();
} else {
PW_LOG_ERROR("Calculation failed: %s", result.status().str());
}
Definition: result.h:174
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:

Result<int> i = GetCount();
if (i.ok()) {
updated_total += *i;
}

Using Result<T, StatusType>::value() when no valid value is present will trigger a PW_ASSERT.

Example:

Result<Foo> result = DoBigCalculationThatCouldFail();
const Foo& foo = result.value(); // Asserts/crashes if no value present
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:

Result<Foo*> result = LookUpTheFoo(arg);
if (!result.ok()) {
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>:

Result<Foo> FooFactory::MakeFoo(int arg) {
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
// Constructing or assigning from Status sets the contained value:
PW_ASSERT(res.ok()); // The Result has a value!
PW_ASSERT(res.status() == pw::OkStatus()); // The Result's status is OK.
PW_ASSERT(*res == pw::Status::NotFound()); // Contained value is NOT_FOUND.
PW_ASSERT(res == pw::Status::NotFound()); // Compares the contained value.
// Use reset() to set the Result's error status:
PW_ASSERT(!res.ok()); // No value is present.
PW_ASSERT(res.status() == pw::Status::Internal());
PW_ASSERT(res != pw::Status::Internal()); // No value to compare equal.
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
TType of the contained value (or void).
StatusTypeStatus type that represents the error. Defaults to pw::Status. Must be derived from pw::StatusBase and use an enum code.
Inheritance diagram for pw::Result< T, StatusType >:

Public Types

using value_type = T
 
using status_type = StatusType
 

Public Member Functions

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 &&
 

Friends

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)
 

Member Typedef Documentation

◆ status_type

template<typename T , typename StatusType >
using pw::Result< T, StatusType >::status_type = StatusType

The status type used to represent the status of this Result. Defaults to pw::Status.

◆ value_type

template<typename T , typename StatusType >
using pw::Result< T, StatusType >::value_type = T

Generic value_type member for use within generic programming. This usage is analogous to that of std::optional::value_type.

Constructor & Destructor Documentation

◆ Result() [1/7]

template<typename T , typename StatusType >
template<typename S = StatusType, typename = std::enable_if_t<std::is_same_v<S, Status>>>
constexpr pw::Result< T, StatusType >::Result ( )
inlineexplicitconstexpr

Constructs a new Result<T> with a pw::Status::Unknown() status.

This constructor is marked explicit to prevent usages in return values (e.g. return {}) under the misconception that Result<std::vector<int>> (for example) will be initialized with an empty vector.

Only enabled when StatusType is pw::Status.

◆ Result() [2/7]

template<typename T , typename StatusType >
constexpr pw::Result< T, StatusType >::Result ( const Result< T, StatusType > &  )
constexprdefault

Result<T, StatusType> is copy constructible if T is copy constructible.

◆ Result() [3/7]

template<typename T , typename StatusType >
constexpr pw::Result< T, StatusType >::Result ( Result< T, StatusType > &&  )
constexprdefault

Result<T, StatusType> is move constructible if T is move constructible.

◆ Result() [4/7]

template<typename T , typename StatusType >
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 pw::Result< T, StatusType >::Result ( const Result< U, StatusType > &  other)
inlineconstexpr

Constructs a new Result<T, StatusType> from a Result<U, StatusType> when T is constructible from U.

To avoid ambiguity, these constructors are disabled if T is also constructible from Result<U, StatusType>. This constructor is explicit if and only if the corresponding construction of T from U is explicit. (This constructor inherits its explicitness from the underlying constructor.)

◆ Result() [5/7]

template<typename T , typename StatusType >
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 pw::Result< T, StatusType >::Result ( U &&  v)
inlineconstexpr

Constructs a new Result<T, StatusType> with a non-OK status.

After calling this constructor, this->ok() will be false and calls to value() will trigger a PW_ASSERT.

The constructor takes any type U that is constructible/convertible to status_type. This constructor is explicit if and only if U is not implicitly convertible to status_type.

Disabled when T is StatusType (in which case constructing from a status initializes the contained value; use reset() to set an error status).

Precondition
!status_type(std::forward<U>(v)).ok(). This requirement is asserted via PW_ASSERT.

◆ Result() [6/7]

template<typename T , typename StatusType >
template<typename... Args>
constexpr pw::Result< T, StatusType >::Result ( std::in_place_t  ,
Args &&...  args 
)
inlineexplicitconstexpr

Constructs the inner value T in-place using the provided args, using the T(args...) constructor.

◆ Result() [7/7]

template<typename T , typename StatusType >
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 pw::Result< T, StatusType >::Result ( U &&  u)
inlineconstexpr

Constructs the inner value T in-place using the provided arg, using the T(U) (direct-initialization) constructor.

Precondition
This constructor is only valid if T can be constructed from a U. Can accept move or copy constructors.

This constructor is explicit if U is not convertible to T. To avoid ambiguity, this constructor is disabled if U is a Result<J, StatusType>, where J is convertible to T.

Member Function Documentation

◆ and_then() [1/4]

template<typename T , typename StatusType >
template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&>, std::enable_if_t< std::is_copy_constructible_v< Ret >, int > = 0>
constexpr Ret pw::Result< T, StatusType >::and_then ( Fn &&  function) &
inlineconstexpr
Returns
The Result from invoking func() on the held value if ok(). Otherwise, returns a Result with the contained error status.

◆ and_then() [2/4]

template<typename T , typename StatusType >
template<typename Fn , typename Ret = internal_result::InvokeResultType<Fn, T&&>, std::enable_if_t< std::is_move_constructible_v< Ret >, int > = 0>
constexpr Ret pw::Result< T, StatusType >::and_then ( Fn &&  function) &&
inlineconstexpr

Returns
The Result from invoking func() on the held value if ok(). Otherwise, returns a Result with the contained error status.

◆ and_then() [3/4]

template<typename T , typename StatusType >
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 pw::Result< T, StatusType >::and_then ( Fn &&  function) const &
inlineconstexpr

Returns
The Result from invoking func() on the held value if ok(). Otherwise, returns a Result with the contained error status.

◆ and_then() [4/4]

template<typename T , typename StatusType >
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 pw::Result< T, StatusType >::and_then ( Fn &&  function) const &&
inlineconstexpr

Returns
The Result from invoking func() on the held value if ok(). Otherwise, returns a Result with the contained error status.

◆ emplace() [1/2]

template<typename T , typename StatusType >
template<typename... Args>
constexpr T & pw::Result< T, StatusType >::emplace ( Args &&...  args)
inlineconstexpr

Reconstructs the inner value T in-place using the provided args, using the T(args...) constructor.

Returns
A reference to the reconstructed T.

◆ emplace() [2/2]

template<typename T , typename StatusType >
template<typename U , typename... Args, std::enable_if_t< std::is_constructible< T, std::initializer_list< U > &, Args &&... >::value, int > = 0>
constexpr T & pw::Result< T, StatusType >::emplace ( std::initializer_list< U >  ilist,
Args &&...  args 
)
inlineconstexpr

Reconstructs the inner value T in-place using the provided args, using the T(args...) constructor.

Returns
A reference to the reconstructed T.

◆ IgnoreError()

template<typename T , typename StatusType >
constexpr void pw::Result< T, StatusType >::IgnoreError ( ) const
inlineconstexpr

Ignores any errors. This method does nothing except potentially suppress complaints from any tools that are checking that errors are not dropped.

◆ ok()

template<typename T , typename StatusType >
constexpr bool pw::Result< T, StatusType >::ok ( ) const
inlineconstexpr
Returns
Whether or not this Result<T, StatusType> holds a T value. This member function is analogous to Status::ok() and should be used similarly to check the status of return values.

Example:

Result<Foo> result = DoBigCalculationThatCouldFail();
if (result.ok()) {
// Handle result
} else {
// Handle error
}

◆ operator*() [1/4]

template<typename T , typename StatusType >
constexpr T && pw::Result< T, StatusType >::operator* ( ) &&
inlineconstexpr

Returns
A reference to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value within the Result<T, StatusType>. Alternatively, see the value() member function for a similar API that guarantees crashing if there is no current value.

◆ operator*() [2/4]

template<typename T , typename StatusType >
constexpr T & pw::Result< T, StatusType >::operator* ( ) &
inlineconstexpr

Returns
A reference to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value within the Result<T, StatusType>. Alternatively, see the value() member function for a similar API that guarantees crashing if there is no current value.

◆ operator*() [3/4]

template<typename T , typename StatusType >
constexpr const T && pw::Result< T, StatusType >::operator* ( ) const &&
inlineconstexpr

Returns
A reference to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value within the Result<T, StatusType>. Alternatively, see the value() member function for a similar API that guarantees crashing if there is no current value.

◆ operator*() [4/4]

template<typename T , typename StatusType >
constexpr const T & pw::Result< T, StatusType >::operator* ( ) const &
inlineconstexpr
Returns
A reference to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value within the Result<T, StatusType>. Alternatively, see the value() member function for a similar API that guarantees crashing if there is no current value.

◆ operator->() [1/2]

template<typename T , typename StatusType >
constexpr const T * pw::Result< T, StatusType >::operator-> ( ) const
inlineconstexpr
Returns
A pointer to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value.

◆ operator->() [2/2]

template<typename T , typename StatusType >
constexpr T * pw::Result< T, StatusType >::operator-> ( )
inlineconstexpr

Returns
A pointer to the current value. Only checks if a value is present if PW_ASSERT_ENABLE_DEBUG is enabled (via PW_DASSERT).
Precondition
this->ok() == true, otherwise the behavior is undefined.

Use this->ok() to verify that there is a current value.

◆ operator=() [1/5]

template<typename T , typename StatusType >
constexpr Result & pw::Result< T, StatusType >::operator= ( const Result< T, StatusType > &  )
constexprdefault

Result<T, StatusType> is copy assignable if T is copy constructible and copy assignable.

◆ operator=() [2/5]

template<typename T , typename StatusType >
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 & pw::Result< T, StatusType >::operator= ( const Result< U, StatusType > &  other)
inlineconstexpr

Assigns a Result<T, StatusType> from a Result<U, StatusType>.

Precondition
These overloads only apply if Result<T, StatusType> is constructible and assignable from Result<U, StatusType> and Result<T, StatusType> cannot be directly assigned from Result<U, StatusType>.
If both Result<T, StatusType> and Result<U, StatusType> are OK, assigns U to T directly.
If Result<T, StatusType> is OK and Result<U, StatusType> contains an error code, destroys the value of Result<T, StatusType> and assigns the error status from Result<U, StatusType>.
If Result<T, StatusType> contains an error code and Result<U, StatusType> is OK, directly initializes T from U.
If both Result<T, StatusType> and Result<U, StatusType> contain an error code, assigns the status in Result<U, StatusType> to Result<T, StatusType>.

◆ operator=() [3/5]

template<typename T , typename StatusType >
constexpr Result & pw::Result< T, StatusType >::operator= ( Result< T, StatusType > &&  )
constexprdefault

Result<T, StatusType> is move assignable if T is move constructible and move assignable.

◆ operator=() [4/5]

template<typename T , typename StatusType >
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 & pw::Result< T, StatusType >::operator= ( U &&  v)
inlineconstexpr

Assigns a non-OK status to this Result<T, StatusType>, destroying any currently held value.

Disabled when T is StatusType (in which case assigning a status updates the contained value; use reset() to set an error status).

Precondition
!status_type(std::forward<U>(v)).ok(). This requirement is asserted via PW_ASSERT.

◆ operator=() [5/5]

template<typename T , typename StatusType >
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 & pw::Result< T, StatusType >::operator= ( U &&  v)
inlineconstexpr

Perfect-forwarding value assignment operator.

If *this contains a T value before the call, the contained value is assigned from std::forward<U>(v). Otherwise, it is directly initialized from std::forward<U>(v).

Precondition
std::is_constructible_v<T, U> is true.
std::is_assignable_v<T&, U> is true.
std::is_same_v<Result<T, StatusType>, std::remove_cvref_t<U>> is false.
Assigning U to T is not ambiguous. If U is Result<V, StatusType> and T is constructible and assignable from both Result<V, StatusType> and V, the assignment is considered bug-prone and ambiguous and thus will fail to compile. For example:
Result<bool> s1 = true; // s1.ok() && *s1 == true
Result<bool> s2 = false; // s2.ok() && *s2 == false
s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`?

◆ or_else() [1/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::or_else ( Fn &&  function) &&
inlineconstexpr

Returns
This Result<T, StatusType> if it has a value, otherwise invokes the given function with status(). The function must return a type convertible to Result<T, StatusType> or void.

◆ or_else() [2/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::or_else ( Fn &&  function) &&
inlineconstexpr

Returns
This Result<T, StatusType> if it has a value, otherwise invokes the given function with status(). The function must return a type convertible to Result<T, StatusType> or void.

◆ or_else() [3/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::or_else ( Fn &&  function) const &
inlineconstexpr
Returns
This Result<T, StatusType> if it has a value, otherwise invokes the given function with status(). The function must return a type convertible to Result<T, StatusType> or void.

◆ or_else() [4/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::or_else ( Fn &&  function) const &
inlineconstexpr

Returns
This Result<T, StatusType> if it has a value, otherwise invokes the given function with status(). The function must return a type convertible to Result<T, StatusType> or void.

◆ reset() [1/3]

template<typename T , typename StatusType >
template<typename status_type::Code kCode>
constexpr void pw::Result< T, StatusType >::reset ( )
inlineconstexpr

Destroys the contained value, if any, and sets the status. The status must not be OK. To avoid a runtime check, use the reset<kCode>() function template whenever possible.

◆ reset() [2/3]

template<typename T , typename StatusType >
template<typename C , std::enable_if_t< std::is_same_v< C, typename status_type::Code >, int > = 0>
constexpr void pw::Result< T, StatusType >::reset ( C  code)
inlineconstexpr

Destroys the contained value, if any, and sets the status. The status must not be OK. To avoid a runtime check, use the reset<kCode>() function template whenever possible.

◆ reset() [3/3]

template<typename T , typename StatusType >
constexpr void pw::Result< T, StatusType >::reset ( status_type  status)
inlineconstexpr

Destroys the contained value, if any, and sets the status. The status must not be OK. To avoid a runtime check, use the reset<kCode>() function template whenever possible.

◆ status()

template<typename T , typename StatusType >
constexpr status_type pw::Result< T, StatusType >::status ( ) const
inlineconstexpr
Returns
The current status_type contained within the Result<T, StatusType>. If Result<T, StatusType> contains a T, then this function returns an OK status (ok() == true).

◆ transform() [1/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::transform ( Fn &&  function) &
inlineconstexpr
Returns
A Result<U, StatusType> containing the result of invoking function on the held value if *this contains a value. Otherwise, returns a Result<U, StatusType> with the same status as *this.

◆ transform() [2/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::transform ( Fn &&  function) &&
inlineconstexpr

Returns
A Result<U, StatusType> containing the result of invoking function on the held value if *this contains a value. Otherwise, returns a Result<U, StatusType> with the same status as *this.

◆ transform() [3/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::transform ( Fn &&  function) const &
inlineconstexpr

Returns
A Result<U, StatusType> containing the result of invoking function on the held value if *this contains a value. Otherwise, returns a Result<U, StatusType> with the same status as *this.

◆ transform() [4/4]

template<typename T , typename StatusType >
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 > pw::Result< T, StatusType >::transform ( Fn &&  function) const &&
inlineconstexpr

Returns
A Result<U, StatusType> containing the result of invoking function on the held value if *this contains a value. Otherwise, returns a Result<U, StatusType> with the same status as *this.

◆ value() [1/4]

template<typename T , typename StatusType >
constexpr T && pw::Result< T, StatusType >::value ( ) &&
inlineconstexpr

Returns
A reference to the held value if this->ok(). Otherwise, terminates the process via PW_ASSERT.

If you have already checked the status using this->ok(), you probably want to use operator*() or operator->() to access the value instead of value.

For value types that are cheap to copy, prefer simple code:

T value = result.value();

Otherwise, if the value type is expensive to copy, but can be left in the Result<T, StatusType>, simply assign to a reference:

T& value = result.value(); // or `const T&`

Otherwise, if the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value();

The std::move on result instead of on the whole expression enables warnings about possible uses of the result object after the move.

◆ value() [2/4]

template<typename T , typename StatusType >
constexpr T & pw::Result< T, StatusType >::value ( ) &
inlineconstexpr

Returns
A reference to the held value if this->ok(). Otherwise, terminates the process via PW_ASSERT.

If you have already checked the status using this->ok(), you probably want to use operator*() or operator->() to access the value instead of value.

For value types that are cheap to copy, prefer simple code:

T value = result.value();

Otherwise, if the value type is expensive to copy, but can be left in the Result<T, StatusType>, simply assign to a reference:

T& value = result.value(); // or `const T&`

Otherwise, if the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value();

The std::move on result instead of on the whole expression enables warnings about possible uses of the result object after the move.

◆ value() [3/4]

template<typename T , typename StatusType >
constexpr const T && pw::Result< T, StatusType >::value ( ) const &&
inlineconstexpr

Returns
A reference to the held value if this->ok(). Otherwise, terminates the process via PW_ASSERT.

If you have already checked the status using this->ok(), you probably want to use operator*() or operator->() to access the value instead of value.

For value types that are cheap to copy, prefer simple code:

T value = result.value();

Otherwise, if the value type is expensive to copy, but can be left in the Result<T, StatusType>, simply assign to a reference:

T& value = result.value(); // or `const T&`

Otherwise, if the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value();

The std::move on result instead of on the whole expression enables warnings about possible uses of the result object after the move.

◆ value() [4/4]

template<typename T , typename StatusType >
constexpr const T & pw::Result< T, StatusType >::value ( ) const &
inlineconstexpr
Returns
A reference to the held value if this->ok(). Otherwise, terminates the process via PW_ASSERT.

If you have already checked the status using this->ok(), you probably want to use operator*() or operator->() to access the value instead of value.

For value types that are cheap to copy, prefer simple code:

T value = result.value();

Otherwise, if the value type is expensive to copy, but can be left in the Result<T, StatusType>, simply assign to a reference:

T& value = result.value(); // or `const T&`

Otherwise, if the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value();

The std::move on result instead of on the whole expression enables warnings about possible uses of the result object after the move.

◆ value_or() [1/2]

template<typename T , typename StatusType >
template<typename U >
constexpr T pw::Result< T, StatusType >::value_or ( U &&  default_value) &&
inlineconstexpr

Returns
The current value if this->ok() == true. Otherwise constructs a value using the provided default_value.

Unlike value, this function returns by value, copying the current value if necessary. If the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value_or(def);

Unlike with value, calling std::move() on the result of value_or will still trigger a copy.

◆ value_or() [2/2]

template<typename T , typename StatusType >
template<typename U >
constexpr T pw::Result< T, StatusType >::value_or ( U &&  default_value) const &
inlineconstexpr
Returns
The current value if this->ok() == true. Otherwise constructs a value using the provided default_value.

Unlike value, this function returns by value, copying the current value if necessary. If the value type supports an efficient move, it can be used as follows:

T value = std::move(result).value_or(def);

Unlike with value, calling std::move() on the result of value_or will still trigger a copy.

Friends And Related Function Documentation

◆ operator!= [1/7]

template<typename T , typename StatusType >
template<typename U = T, std::enable_if_t< internal_result::IsEqualityComparable< U, U >::value, int > = 0>
constexpr bool operator!= ( const Result< T, StatusType > &  lhs,
const Result< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [2/7]

template<typename T , typename StatusType >
template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0>
constexpr bool operator!= ( const Result< T, StatusType > &  lhs,
const U &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [3/7]

template<typename T , typename StatusType >
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< T, StatusType > &  lhs,
status_type  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [4/7]

template<typename T , typename StatusType >
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< T, StatusType > &  lhs,
typename status_type::Code  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [5/7]

template<typename T , typename StatusType >
template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0>
constexpr bool operator!= ( const U &  lhs,
const Result< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [6/7]

template<typename T , typename StatusType >
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< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator!= [7/7]

template<typename T , typename StatusType >
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< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator== [1/7]

template<typename T , typename StatusType >
template<typename U = T, std::enable_if_t< internal_result::IsEqualityComparable< U, U >::value, int > = 0>
constexpr bool operator== ( const Result< T, StatusType > &  lhs,
const Result< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator== [2/7]

template<typename T , typename StatusType >
template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0>
constexpr bool operator== ( const Result< T, StatusType > &  lhs,
const U &  rhs 
)
friend

Checks equality of a Result<T, StatusType> and a value. A Result without a value never compares equal to a value. This overload is only enabled if T is equality comparable with U, and U is not a Result, status, or status code (unless T itself is StatusType or StatusType::Code).

◆ operator== [3/7]

template<typename T , typename StatusType >
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< T, StatusType > &  lhs,
status_type  rhs 
)
friend

Compares the status of a Result<T, StatusType> with a status. A Result holding a value compares equal to an OK status.

Disabled when T is StatusType (in which case operator== compares against the held StatusType value).

◆ operator== [4/7]

template<typename T , typename StatusType >
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< T, StatusType > &  lhs,
typename status_type::Code  rhs 
)
friend

Compares the status of a Result<T, StatusType> with a status code.

Disabled when T is StatusType or StatusType::Code (in which case operator== compares against the held value).

◆ operator== [5/7]

template<typename T , typename StatusType >
template<typename U , std::enable_if_t< internal_result::IsValueComparisonValid< T, U, StatusType >::value, int > = 0>
constexpr bool operator== ( const U &  lhs,
const Result< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator== [6/7]

template<typename T , typename StatusType >
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< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.

◆ operator== [7/7]

template<typename T , typename StatusType >
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< T, StatusType > &  rhs 
)
friend

Checks the equality of two Result<T, StatusType> objects. Only enabled if T is equality comparable.


The documentation for this class was generated from the following file: