///////////////////////////////////////////////////////////////////////////// /// \brief The class template result
manages result results from APIs, /// while encoding possible failure conditions. /// /// A common use-case for result is the return value of a function that /// may fail. As opposed to other approaches, such as std::pair<T,bool>
/// or std::optional
, result
more accurately conveys the intent of the /// user along with the failure condition to the caller. This effectively /// produces an orthogonal error handling mechanism that allows for exception /// safety while also allowing discrete testability of the return type. /// /// result<T,E>
types may contain a T
value, which signifies that an /// operation succeeded in producing the result value of type T
. If an /// result
does not contain a T
value, it will always contain an E
/// error condition instead. /// /// An result<T,E>
can always be queried for a possible error case by /// calling the error()
function, even if it contains a value. /// In the case that a result<T,E>
contains a value object, this will /// simply return an E
object constructed through default aggregate /// construction, as if through the expression E{}
, which is assumed to be /// a “valid” (no-error) state for an E
type. /// For example: /// /// * std::error_code{}
produces a default-construct error-code, which is /// the “no error” state, /// * integral (or enum) error codes produce a 0
value (no error), thanks to /// zero-initialization, /// * std::exception_ptr{}
produces a null-pointer, /// * std::string{}
produces an empty string ""
, /// * etc. /// /// When a result<T,E>
contains either a value or error, the storage for /// that object is guaranteed to be allocated as part of the result /// object’s footprint, i.e. no dynamic memory allocation ever takes place. /// Thus, a result object models an object, not a pointer, even though the /// operator*()
and operator->()
are defined. /// /// When an object of type result<T,E>
is contextually converted to /// bool
, the conversion returns true
if the object contains a value and /// false
if it contains an error. /// /// result
objects do not have a “valueless” state like variant
s do. /// Once a result
has been constructed with a value or error, the /// active underlying type can only be changed through assignment which may /// is only enabled if construction is guaranteed to be non-throwing. This /// ensures that a valueless state cannot occur naturally. /// /// Example Use: /// \code /// auto to_string(int x) -> resultstd::string /// { /// try { /// return std::stoi(x); /// } catch (const std::invalid_argument&) { /// return fail(std::errc::invalid_argument); /// } catch (const std::std::out_of_range&) { /// return fail(std::errc::result_out_of_range); /// } /// } /// \endcode /// /// \note If using C++17 or above, fail
can be replaced with /// failure{...}
thanks to CTAD. /// /// \tparam T the underlying value type /// \tparam E the underlying error type ///////////////////////////////////////////////////////////////////////////
Class result<T, E>
#include <Geode/external/result/result.hpp>
Examples0
Public static methods0
Public member functions16
cpp::bitwizeshift::result&operator=()
/// \brief Copy assigns the result stored in \p other /// /// \note This assignment operator only participates in overload resolution /// if the following conditions are met: /// - std::is_nothrow_copy_constructible_v<T>
is true
, and /// - std::is_nothrow_copy_constructible_v<E>
is true
/// this restriction guarantees that no ’ /// /// \note This assignment operator is defined as trivial if the following /// conditions are all true
: /// - std::is_trivially_copy_constructible<T>::value
/// - std::is_trivially_copy_constructible<E>::value
/// - std::is_trivially_copy_assignable<T>::value
/// - std::is_trivially_copy_assignable<E>::value
/// - std::is_trivially_destructible<T>::value
/// - std::is_trivially_destructible<E>::value
/// /// \param other the other result to copy
cpp::bitwizeshift::result&operator=()
/// \brief Move assigns the result stored in \p other /// /// \note This assignment operator only participates in overload resolution /// if the following conditions are met: /// - /// { /// \brief Retrieves a pointer to the contained value /// /// This operator exists to give /// { /// \brief Retrieves a reference to the contained value /// /// This operator exists to give /// \brief Returns /// \brief Returns /// { /// \brief Returns a reference to the contained value /// /// This function provides checked (throwing) access to the underlying /// value. The constness and refness of this result is propagated to the /// underlying reference. /// /// If this contains an error, an exception is thrown containing the /// underlying error. The error is consumed propagating the same constness /// and refness of this result. /// /// ### Examples /// /// Basic Usage: /// /// /// { /// \brief Returns the contained error, if one exists, or a /// default-constructed error value /// /// The std::is_nothrow_copy_constructible_v<T>
is true
, and /// - std::is_nothrow_copy_constructible_v<E>
is true
/// this restriction guarantees that no ’valueless_by_exceptionstate /// may occur. /// /// \note This assignment operator is defined as trivial if the following /// conditions are all
true: /// -
std::is_trivially_move_constructible/// -
std::is_trivially_move_constructible/// -
std::is_trivially_move_assignable/// -
std::is_trivially_move_assignable/// -
std::is_trivially_destructible/// -
std::is_trivially_destructibletypename std::remove_reference<T>::type*operator->()
result
an optional
-like API for cases /// where it’s known that the result
already contains a value. /// /// Care must be taken to ensure that this is only used in safe contexts /// where a T
value is active. /// /// \note The behavior is undefined if *this
does not contain a value. /// /// ### Examples /// /// Basic Usage: /// /// cpp /// auto r = cpp::result<Widget,int>{ /// make_widget() /// }; /// /// r->do_something(); ///
/// /// \return a pointer to the contained valuetypename std::remove_reference<typename std::add_const<T>::type>::type*operator->()const
typename std::add_lvalue_reference<T>::typeoperator*()
result
an optional
-like API for cases /// where it’s known that the result
already contains a value. /// /// Care must be taken to ensure that this is only used in safe contexts /// where a T
value is active. /// /// \note The behaviour is undefined if *this
does not contain a value /// /// ### Examples /// /// Basic Usage: /// /// cpp /// auto r = cpp::result<Widget,int>{ /// make_widget() /// }; /// /// (*r).do_something(); /// /// consume(*r); ///
/// /// \return a reference to the contained valuetypename std::add_rvalue_reference<T>::typeoperator*()
typename std::add_lvalue_reference<typename std::add_const<T>::type>::typeoperator*()const
typename std::add_rvalue_reference<typename std::add_const<T>::type>::typeoperator*()const
boolhas_value()const
true
if *this
contains a value /// /// ### Examples /// /// Basic Usage: /// /// cpp /// auto get_result() -> cpp::result<int, int>; /// auto r = get_result(); /// if (r.has_value()) { ... } /// /// assert(cpp::result<int,int>{42}.has_value()); /// /// assert(!cpp::result<int,int>{cpp::fail(42)}.has_value()); ///
/// /// \return true
if *this
contains a value, false
if *this
/// contains an errorboolhas_error()const
true
if *this
contains an error /// /// ### Examples /// /// Basic Usage: /// /// cpp /// auto get_result() -> cpp::result<int, int>; /// /// auto r = get_result(); /// if (r.has_error()) { ... } /// /// assert(!cpp::result<int,int>{42}.has_error()); /// /// assert(cpp::result<int,int>{cpp::fail(42)}.has_error()); ///
/// /// \return true
if *this
contains an error, false
if *this
/// contains a valuetypename std::add_lvalue_reference<T>::typevalue()
cpp /// assert(cpp::result<int,int>{42}.value() == 42); /// /// auto r = cpp::result<std::unique_ptr<int>,int>{ /// std::make_unique<int>(42) /// }; /// auto s = std::move(r).value(); /// /// try { /// auto r = cpp::result<int,int>{ cpp::fail(42) }; /// auto v = r.value(); /// } catch (const cpp::bad_result_access<int>& e) { /// assert(e.error() == 42); /// } ///
/// /// \throws bad_result_access*this
does not contain a value. /// /// \return the value of *this
typename std::add_rvalue_reference<T>::typevalue()
typename std::add_lvalue_reference<typename std::add_const<T>::type>::typevalue()const
typename std::add_rvalue_reference<typename std::add_const<T>::type>::typevalue()const
Eerror()const
error()
function will not throw any exceptions if E
does not /// throw any exceptions for the copy or move construction. /// /// This is to limit the possible scope for exceptions, and to allow the /// error type to be treated as a “status”-like type, where the /// default-constructed case is considered the “good” state. /// /// If this function is invoked on an rvalue of a result, the error is /// returned via move-construction /// /// ### Requires /// /// * std::is_default_constructible<E>::value
is true
/// * std::is_copy_constructible<E>::value
or /// std::is_move_constructible<E>::value
is true
/// * E{}
represents the “good” (non-error) state /// /// ### Examples /// /// Basic Usage: /// /// cpp /// auto r = cpp::result<int,std::error_code>{ 42 }; /// assert(r.error() == std::error_code{}); /// /// auto r = cpp::result<int,std::error_code>{ /// cpp::fail(std::io_errc::stream) /// }; /// /// assert(r.error() == std::io_errc::stream); ///
/// /// \return the error or a default-constructed error valueEerror()
Fields0
Protected member functions0
Protected fields0