4.6.0
Freundlich's C++ toolkit
|
An optional with an error type.
The downside of exceptions, which are the usual way to handle errors in C++, is that they do not appear in the type system. If a function changes which exceptions it throws, all the code that uses the function will still compile. This can make keeping track of which errors to handle where extremely difficult. Instead of having a function that throws an exception, i.e.
we can move the exception into the return type instead, like so:
In the first example, where the exception is used, a caller has to know that such an exception may be thrown and catch it.
In the second example, where the either is used, we cannot ignore that an error can occur. The simplest way to deconstruct an either<F,S>
is to call the fcppt::either::match function. It gets two lambdas, where the first one receives F
and the second one receives S
.
In general, an either<F,S>
is basically the same as a std::variant<F,S>
but with additional meaning assigned to F
and S
. This becomes apparant in functions like fcppt::either::map, fcppt::either::apply and fcppt::either::bind.
The simplest operation on eithers is fcppt::either::map. It allows us to transform the success value while keeping the error value. For example, consider a function that might return an int, which we want to transform into a string. This can be done as follows:
We often have to chain multiple eithers together. For example, if we want to call two functions, each of which can fail, we only want to produce a result if both succeeed. This can be done with fcppt::either::apply.
Note that since fcppt::either::apply is a variadic template, so it can work on arbitrarly many eithers, the function is its first parameter.
Another, even more basic operation, is fcppt::either::bind. As an example, let us look at how reading from a std::istream
would work using eithers. Consider a function that tries to read an int and if that succeeds tries to read a string.
First note that the function reading from the stream, which is operator>>
, uses a reference parameter to store its result. Since operator>>
returns a reference to _stream
, the expression !(_stream >> something)
checks if reading something
produced an error. If that is the case, we cannot use the stream to read more data, and we need to abort early.
To do this with eithers instead, first, let us encapsulate reading a single value in a template function which returns an either.
Then, we can use this function to read the two eithers in succession, which is done using fcppt::either::bind.
Note that the difference to using fcppt::either::apply is that the second operation is not done if the first one returned an error. Unfortunately, chaining more of these operations together creates more and more nested code. In other programming languages like Haskell, there is special notation to bring every operation on the same indentation level, called the Do-Notation.
If at some point you want to turn an either back into an exception, you can use fcppt::either::to_exception.
When functions return optional errors but no success values, it can be more convenient to handle such cases as eithers. An fcppt::either::error is an either with a success type that only has one value, which is fcppt::unit. For example:
Header file | Description |
---|---|
object_fwd.hpp | Contains fcppt::either::object either's declaration. |
object_decl.hpp | Contains fcppt::either::object either's definition. |
object_impl.hpp | Contains the definition of fcppt::either::object either's member functions. |
object.hpp | Includes object_impl.hpp and comparison.hpp . |
apply.hpp | Contains fcppt::either::apply. |
bind.hpp | Contains fcppt::either::bind. |
comparison.hpp | Contains operator== and operator!= . |
error_fwd.hpp | Contains fcppt::either::error error's declaration. |
error.hpp | Contains fcppt::either::error error's definition. |
error_from_optional.hpp | Contains fcppt::either::error_from_optional. |
failure_opt.hpp | Contains fcppt::either::failure_opt. |
first_success.hpp | Contains fcppt::either::first_success. |
from_optional.hpp | Contains fcppt::either::from_optional. |
make_failure.hpp | Contains fcppt::either::make_failure. |
make_success.hpp | Contains fcppt::either::make_success. |
map.hpp | Contains fcppt::either::map. |
map_failure.hpp | Contains fcppt::either::map_failure. |
match.hpp | Contains fcppt::either::match. |
no_error_fwd.hpp | Contains fcppt::either::no_error no_error's declaration. |
no_error.hpp | Contains fcppt::either::no_error no_error's definition. |
output.hpp | Contains operator<< . |
sequence.hpp | Contains fcppt::either::sequence. |
sequence_error.hpp | Contains fcppt::either::sequence_error. |
success_opt.hpp | Contains fcppt::either::success_opt. |
to_exception.hpp | Contains fcppt::either::to_exception. |
try_call.hpp | Contains fcppt::either::try_call. |
Classes | |
class | fcppt::either::object< Failure, Success > |
Typedefs | |
template<typename Failure > | |
using | fcppt::either::error = fcppt::either::object<Failure, fcppt::either::no_error> |
An either without a success value. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::failure_move_type |
The moved failure type of an either. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::failure_reference_type = decltype(std::declval<Either>().get_failure_unsafe()) |
The failure reference type of an either. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::failure_type = typename std::remove_cvref_t<Either>::failure |
The failure type of an either. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::success_move_type |
The moved success type of an either. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::success_reference_type = decltype(std::declval<Either>().get_success_unsafe()) |
The success reference type of an either. | |
template<fcppt::either::object_concept Either> | |
using | fcppt::either::success_type = typename std::remove_cvref_t<Either>::success |
The success type of an either. | |
Functions | |
template<fcppt::either::object_concept Either1, fcppt::either::object_concept... Eithers, fcppt::concepts::invocable_move< fcppt::either::success_move_type< Either1 >, fcppt::either::success_move_type< Eithers >... > Function> requires ( std::is_same_v<fcppt::either::failure_type<Either1>, fcppt::either::failure_type<Eithers>> &&...) | |
fcppt::either::object< fcppt::either::failure_type< Either1 >, std::invoke_result_t< Function, fcppt::either::success_move_type< Either1 >, fcppt::either::success_move_type< Eithers >... > > | fcppt::either::apply (Function const &_function, Either1 &&_either1, Eithers &&..._eithers) |
Applies a function to several eithers. | |
template<fcppt::either::object_concept Either, fcppt::concepts::invocable_move< fcppt::either::success_move_type< Either > > Function> requires fcppt::either::is_object_v< std::invoke_result_t<Function, fcppt::either::success_move_type<Either>>> && std::is_same_v< fcppt::either::failure_type<Either>, fcppt::either::failure_type< std::invoke_result_t<Function, fcppt::either::success_move_type<Either>>>> | |
std::invoke_result_t< Function, fcppt::either::success_move_type< Either > > | fcppt::either::bind (Either &&_either, Function const &_function) |
Monadic bind on the success type of an either. | |
template<typename Failure , typename Success > | |
bool | fcppt::either::operator== (fcppt::either::object< Failure, Success > const &_a, fcppt::either::object< Failure, Success > const &_b) |
Compares two eithers for equality. | |
template<typename Failure , typename Success > | |
bool | fcppt::either::operator!= (fcppt::either::object< Failure, Success > const &_a, fcppt::either::object< Failure, Success > const &_b) |
Compares two eithers for inequality. | |
template<fcppt::concepts::invocable_move Failure, fcppt::concepts::invocable_move Success> | |
fcppt::either::object< std::invoke_result_t< Failure >, std::invoke_result_t< Success > > | fcppt::either::construct (bool const _value, Success const &_success, Failure const &_failure) |
Constructs an either by calling one of two functions. | |
template<fcppt::optional::object_concept Optional> | |
fcppt::either::error< fcppt::optional::value_type< Optional > > | fcppt::either::error_from_optional (Optional &&_optional) |
Converts an optional error to an either. | |
template<fcppt::either::object_concept Either> | |
fcppt::optional::object< fcppt::either::failure_type< Either > > | fcppt::either::failure_opt (Either &&_either) |
Returns the failure type as an optional. | |
template<typename Functions > requires fcppt::concepts::invocable_move<fcppt::type_traits::value_type<Functions>> && fcppt::either::is_object_v<std::invoke_result_t<fcppt::type_traits::value_type<Functions>>> | |
fcppt::either::object< std::vector< fcppt::either::failure_type< std::invoke_result_t< fcppt::type_traits::value_type< Functions > > > >, fcppt::either::success_type< std::invoke_result_t< fcppt::type_traits::value_type< Functions > > > > | fcppt::either::first_success (Functions const &_functions) |
Call a container of functions, returning their first success or a container of failures. | |
template<fcppt::optional::object_concept Optional, fcppt::concepts::invocable_move FailureFunction> | |
fcppt::either::object< std::invoke_result_t< FailureFunction >, fcppt::optional::value_type< Optional > > | fcppt::either::from_optional (Optional &&_optional, FailureFunction const &_failure_function) |
Converts an optional to an either. | |
template<fcppt::either::object_concept Either> requires fcppt::either::is_object_v<fcppt::either::success_type<Either>> && std::is_same_v< fcppt::either::failure_type<Either>, fcppt::either::failure_type<fcppt::either::success_type<Either>>> | |
fcppt::either::object< fcppt::either::failure_type< Either >, fcppt::either::success_type< fcppt::either::success_type< Either > > > | fcppt::either::join (Either &&_either) |
Removes one layer of eithers. | |
template<fcppt::concepts::invocable_move Next, fcppt::concepts::invocable< fcppt::either::success_type< std::invoke_result_t< Next > > > Loop> requires fcppt::either::is_object_v<std::invoke_result_t<Next>> | |
fcppt::either::failure_type< std::invoke_result_t< Next > > | fcppt::either::loop (Next const &_next, Loop const &_loop) |
Loops a function returning an either. | |
template<fcppt::concepts::move_constructible Success, typename Failure > | |
fcppt::either::object< std::remove_cvref_t< Failure >, Success > | fcppt::either::make_failure (Failure &&_failure) |
Create an either with a failure. | |
template<fcppt::concepts::move_constructible Failure, typename Success > | |
fcppt::either::object< Failure, std::remove_cvref_t< Success > > | fcppt::either::make_success (Success &&_success) |
Create an either with a success. | |
template<fcppt::either::object_concept Either, fcppt::concepts::invocable_move< fcppt::either::success_move_type< Either > > Function> | |
fcppt::either::object< fcppt::either::failure_type< Either >, std::invoke_result_t< Function, fcppt::either::success_move_type< Either > > > | fcppt::either::map (Either &&_either, Function const &_function) |
Maps over the success type of an either. | |
template<fcppt::either::object_concept Either, fcppt::concepts::invocable_move< fcppt::either::failure_move_type< Either > > Function> | |
fcppt::either::object< std::invoke_result_t< Function, fcppt::either::failure_move_type< Either > >, fcppt::either::success_type< Either > > | fcppt::either::map_failure (Either &&_either, Function const &_function) |
Maps over the failure type of an either. | |
template<fcppt::either::object_concept Either, fcppt::concepts::invocable< fcppt::either::failure_move_type< Either > > FailureFunction, fcppt::concepts::invocable< fcppt::either::success_move_type< Either > > SuccessFunction> requires std::is_same_v< std::invoke_result_t<SuccessFunction, fcppt::either::success_move_type<Either>>, std::invoke_result_t<FailureFunction, fcppt::either::failure_move_type<Either>>> | |
std::invoke_result_t< SuccessFunction, fcppt::either::success_move_type< Either > > | fcppt::either::match (Either &&_either, FailureFunction const &_failure_function, SuccessFunction const &_success_function) |
Matches on the two cases of an either. | |
bool | fcppt::either::operator== (fcppt::either::no_error const &, fcppt::either::no_error const &) |
Comparison of fcppt::either::no_error. | |
template<typename Ch , typename Traits > | |
std::basic_ostream< Ch, Traits > & | fcppt::either::operator<< (std::basic_ostream< Ch, Traits > &_stream, fcppt::either::no_error const &) |
Outputs fcppt::either::no_error. | |
template<typename Failure , typename Success , typename Ch , typename Traits > | |
std::basic_ostream< Ch, Traits > & | fcppt::either::operator<< (std::basic_ostream< Ch, Traits > &_stream, fcppt::either::object< Failure, Success > const &_either) |
Outputs an either to a basic_ostream. | |
template<fcppt::either::object_concept Result, typename Source > | |
Result | fcppt::either::sequence (Source &&_source) |
Sequences a container of eithers. | |
template<typename Sequence , fcppt::concepts::invocable_move< fcppt::container::to_value_type< std::remove_reference_t< Sequence > > > Function> requires fcppt::either::is_object_v<std::invoke_result_t< Function, fcppt::container::to_value_type<std::remove_reference_t<Sequence>>>> && std::is_same_v< fcppt::either::success_type<std::invoke_result_t< Function, fcppt::container::to_value_type<std::remove_reference_t<Sequence>>>>, fcppt::either::no_error> | |
std::invoke_result_t< Function, fcppt::container::to_value_type< std::remove_reference_t< Sequence > > > | fcppt::either::sequence_error (Sequence &&_sequence, Function const &_function) |
Folds over a range, breaking out on the first error. | |
template<fcppt::either::object_concept Either> | |
fcppt::optional::object< fcppt::either::success_type< Either > > | fcppt::either::success_opt (Either &&_either) |
Returns the success type as an optional. | |
template<fcppt::either::object_concept Either, fcppt::concepts::invocable_move< fcppt::either::failure_move_type< Either > > MakeException> | |
fcppt::either::success_move_type< Either > | fcppt::either::to_exception (Either &&_either, MakeException const _make_exception) |
Returns the success value contained in an either or throws an exception. | |
template<fcppt::concepts::move_constructible Exception, fcppt::concepts::invocable_move Function, fcppt::concepts::invocable_move< Exception > ToException> | |
FCPPT_PP_PUSH_WARNING fcppt::either::object< std::invoke_result_t< ToException, Exception >, std::invoke_result_t< Function > > | fcppt::either::try_call (Function const &_function, ToException const &_to_exception) |
Catches exceptions of a function call and puts the result in an either. | |
Variables | |
template<typename T > | |
constexpr bool | fcppt::either::is_object_v = fcppt::either::is_object<T>::value |
Checks if a given type is an fcppt::either::object. | |
using fcppt::either::error = fcppt::either::object<Failure, fcppt::either::no_error> |
An either without a success value.
An either with a failure but no success value. This is useful in case errors are returned as optionals.
using fcppt::either::failure_move_type |
The moved failure type of an either.
using fcppt::either::failure_reference_type = decltype(std::declval<Either>().get_failure_unsafe()) |
The failure reference type of an either.
using fcppt::either::failure_type = typename std::remove_cvref_t<Either>::failure |
The failure type of an either.
using fcppt::either::success_move_type |
The moved success type of an either.
using fcppt::either::success_reference_type = decltype(std::declval<Either>().get_success_unsafe()) |
The success reference type of an either.
using fcppt::either::success_type = typename std::remove_cvref_t<Either>::success |
The success type of an either.
|
nodiscard |
Applies a function to several eithers.
For eithers e_1 = _either1
and e_2, ..., e_n = _eithers
. If there is a smallest i
such that e_i
is set to failure f
, then f
is returned. Otherwise, e_1, ...., e_n
are set to successes s_1,...,s_n
and the result is _function(s_1,...,s_n)
.
|
nodiscard |
Monadic bind on the success type of an either.
If _either is set to success s
, then _function(s)
is returned. Otherwise, the failure in _either is returned.
|
nodiscard |
Constructs an either by calling one of two functions.
If _value is true then _success()
is returned. Otherwise, _failure()
is returned.
|
nodiscard |
Converts an optional error to an either.
If _optional is set to x
, then x
is returned as the failure value.
|
nodiscard |
Returns the failure type as an optional.
|
nodiscard |
Call a container of functions, returning their first success or a container of failures.
For _functions = (f_1,...,f_n)
, let i
be the smallest index such that f_i()
returns success s
, in which case the result is s
. If there is no such index, then all functions return failures e_1,...,e_n
and the result is (e_1,...,_e_n)
.
Functions | A container of functions callable as fcppt::either::object<F,S> () |
TODO(concepts)
|
nodiscard |
Converts an optional to an either.
If _optional is set to x
, then x
is returned as the success value, otherwise _failure_function()
is returned as the failure value.
FailureFunction | Must be a function callable as R () where R is the failure type |
fcppt::either::object< fcppt::either::failure_type< Either >, fcppt::either::success_type< fcppt::either::success_type< Either > > > fcppt::either::join | ( | Either && | _either | ) |
Removes one layer of eithers.
If the outer either has failure f_1
, then f_1
is returned. Otherwise, if the inner either has failure f_2
, then f_2
is returned. Otherwise, the success value of the inner either is returned.
|
nodiscard |
Loops a function returning an either.
Calls _next repeatedly until it returns a failure, which is then returned as the result. Each success value that is returned until then is passed to _loop.
|
inlinenodiscard |
Create an either with a failure.
Success | The success type of the either. |
|
inlinenodiscard |
Create an either with a success.
Failure | The failure type of the either. |
|
nodiscard |
Maps over the success type of an either.
If _either is set to success s
, r = _function(s)
is called and the result is either<Either::failure,decltype(r)>(r)
. Otherwise, the failure in _either is returned.
fcppt::either::object< std::invoke_result_t< Function, fcppt::either::failure_move_type< Either > >, fcppt::either::success_type< Either > > fcppt::either::map_failure | ( | Either && | _either, |
Function const & | _function ) |
Maps over the failure type of an either.
If _either is set to failure f
, r = _function(f)
is called and the result is either<decltype(r),Either::success>(r)
. Otherwise, the success in _either is returned.
|
nodiscard |
Matches on the two cases of an either.
If _either is set to success s
, then _success_function(s)
is returned. Otherwise, _either is set to failure f
and _failure_function(f)
is returned.
|
nodiscard |
Compares two eithers for inequality.
TODO(concepts)
|
inline |
Outputs fcppt::either::no_error.
std::basic_ostream< Ch, Traits > & fcppt::either::operator<< | ( | std::basic_ostream< Ch, Traits > & | _stream, |
fcppt::either::object< Failure, Success > const & | _either ) |
Outputs an either to a basic_ostream.
TODO(concepts)
|
inlinenodiscard |
Comparison of fcppt::either::no_error.
|
nodiscard |
Compares two eithers for equality.
TODO(concepts)
|
nodiscard |
Sequences a container of eithers.
Let _source be a container [e_1,...e_n]
, where e_i
has type fcppt::either::object<F,S_i>
. If there is an i
such that e_i
has failure f
and there is no j < i
such that e_j
has a failure, then f
is returned. Otherwise, all eithers have success values, [s_1,...,s_n]
, and Result{s_1,...,s_n}
is returned.
TODO(concepts)
|
nodiscard |
Folds over a range, breaking out on the first error.
This function is similar to fcppt::either::sequence, except it does not produce an output sequence. Instead, _function returns fcppt::either::error, which on success contains an fcppt::unit. Let _sequence = [x_1, ..., x_n]
. The algorithms calls _function(x_1), ..., _function(x_i)
, where _function(x_i)
is either the first call that returns a failure, in which case the failure is returned as the result, or i=n
, in which case success is returned.
Sequence | Must be a range. |
TODO(concepts)
|
nodiscard |
Returns the success type as an optional.
|
inlinenodiscard |
Returns the success value contained in an either or throws an exception.
If _either is set to success s
, then s
is returned. Otherwise, _either is set to failure f
and the result of _make_exception(f)
is thrown as an exception.
|
nodiscard |
Catches exceptions of a function call and puts the result in an either.
Calls _function in a try block. If _function returns s
, then the result is success s
. If the function throws an exception e
of type Exception, then the result is the failure _to_exception(e)
.
Exception | The exception type to be caught. |
|
inlineconstexpr |
Checks if a given type is an fcppt::either::object.