|
template<class B = Base, class = decltype(B{})> |
| Expected () noexcept(noexcept(B{})) |
|
| Expected (const Expected &that)=default |
|
| Expected (Expected &&that)=default |
|
template<class V , class E , bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(!std::is_same< Expected< V, E >, Expected >::value &&std::is_constructible< Value, V && >::value &&std::is_constructible< Error, E && >::value)), int >::type = 0> |
| Expected (Expected< V, E > that) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_copy_constructible< Value >::value)), int >::type = 0> |
constexpr | Expected (const Value &val) noexcept(noexcept(Value(val))) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_move_constructible< Value >::value)), int >::type = 0> |
constexpr | Expected (Value &&val) noexcept(noexcept(Value(std::move(val)))) |
|
template<class T , bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_convertible< T, Value >::value &&!std::is_convertible< T, Error >::value)), int >::type = 0> |
constexpr | Expected (T &&val) noexcept(noexcept(Value(static_cast< T && >(val)))) |
|
template<class... Ts, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_constructible< Value, Ts &&... >::value)), int >::type = 0> |
constexpr | Expected (in_place_t, Ts &&...ts) noexcept(noexcept(Value(std::declval< Ts >()...))) |
|
template<class U , class... Ts, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_constructible< Value, std::initializer_list< U > &, Ts &&... >::value)), int >::type = 0> |
constexpr | Expected (in_place_t, std::initializer_list< U > il, Ts &&...ts) noexcept(noexcept(Value(std::declval< Ts >()...))) |
|
| Expected (const Error &)=delete |
|
| Expected (Error &&)=delete |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_copy_constructible< Error >::value)), int >::type = 0> |
constexpr | Expected (unexpected_t, const Error &err) noexcept(noexcept(Error(err))) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_move_constructible< Error >::value)), int >::type = 0> |
constexpr | Expected (unexpected_t, Error &&err) noexcept(noexcept(Error(std::move(err)))) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_copy_constructible< Error >::value)), int >::type = 0> |
constexpr | Expected (const Unexpected< Error > &err) noexcept(noexcept(Error(err.error()))) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_move_constructible< Error >::value)), int >::type = 0> |
constexpr | Expected (Unexpected< Error > &&err) noexcept(noexcept(Error(std::move(err.error())))) |
|
Expected & | operator= (const Expected &that)=default |
|
Expected & | operator= (Expected &&that)=default |
|
template<class V , class E , bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(!std::is_same< Expected< V, E >, Expected >::value &&expected_detail::IsConvertible< V &&, Value >::value &&expected_detail::IsConvertible< E &&, Error >::value)), int >::type = 0> |
Expected & | operator= (Expected< V, E > that) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(expected_detail::IsCopyable< Value >::value)), int >::type = 0> |
Expected & | operator= (const Value &val) noexcept(expected_detail::IsNothrowCopyable< Value >::value) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(expected_detail::IsMovable< Value >::value)), int >::type = 0> |
Expected & | operator= (Value &&val) noexcept(expected_detail::IsNothrowMovable< Value >::value) |
|
template<class T , bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_convertible< T, Value >::value &&!std::is_convertible< T, Error >::value)), int >::type = 0> |
Expected & | operator= (T &&val) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(expected_detail::IsCopyable< Error >::value)), int >::type = 0> |
Expected & | operator= (const Unexpected< Error > &err) noexcept(expected_detail::IsNothrowCopyable< Error >::value) |
|
template<bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(expected_detail::IsMovable< Error >::value)), int >::type = 0> |
Expected & | operator= (Unexpected< Error > &&err) noexcept(expected_detail::IsNothrowMovable< Error >::value) |
|
| Expected (const expected_detail::PromiseReturn< Value, Error > &p) |
|
template<class... Ts, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(std::is_constructible< Value, Ts &&... >::value)), int >::type = 0> |
void | emplace (Ts &&...ts) |
|
void | swap (Expected &that) noexcept(expected_detail::StrictAllOf< IsNothrowSwappable, Value, Error >::value) |
|
Expected & | operator= (const Error &)=delete |
|
Expected & | operator= (Error &&)=delete |
|
constexpr bool | hasValue () const noexcept |
|
constexpr bool | hasError () const noexcept |
|
const Value & | value () const & |
|
Value & | value ()& |
|
Value && | value ()&& |
|
const Error & | error () const & |
|
Error & | error ()& |
|
Error && | error ()&& |
|
template<class U > |
Value | value_or (U &&dflt) const & |
|
template<class U > |
Value | value_or (U &&dflt)&& |
|
constexpr | operator bool () const noexcept |
|
const Value & | operator* () const & |
|
Value & | operator* ()& |
|
Value && | operator* ()&& |
|
const Value * | operator-> () const |
|
Value * | operator-> () |
|
const Value * | get_pointer () const &noexcept |
|
Value * | get_pointer ()&noexcept |
|
Value * | get_pointer ()&&=delete |
|
template<class... Fns, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(sizeof...(Fns) > = 1> |
auto | then (Fns &&...fns) const &-> decltype(expected_detail::ExpectedHelper::then_(std::declval< const Base & >(), std::declval< Fns >()...)) |
|
template<class... Fns, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(sizeof...(Fns) > = 1> |
auto | then (Fns &&...fns)&-> decltype(expected_detail::ExpectedHelper::then_(std::declval< Base & >(), std::declval< Fns >()...)) |
|
template<class... Fns, bool FB_CONCATENATE = false, typename std::enable_if< (FB_CONCATENATE(FB_CONCATENATE(Folly, Requires), __LINE__)||static_cast< bool >(sizeof...(Fns) > = 1> |
auto | then (Fns &&...fns)&&-> decltype(expected_detail::ExpectedHelper::then_(std::declval< Base && >(), std::declval< Fns >()...)) |
|
template<class Yes , class No = MakeBadExpectedAccess> |
auto | thenOrThrow (Yes &&yes, No &&no=No{}) const &-> decltype(std::declval< Yes >()(std::declval< const Value & >())) |
|
template<class Yes , class No = MakeBadExpectedAccess> |
auto | thenOrThrow (Yes &&yes, No &&no=No{})&-> decltype(std::declval< Yes >()(std::declval< Value & >())) |
|
template<class Yes , class No = MakeBadExpectedAccess> |
auto | thenOrThrow (Yes &&yes, No &&no=No{})&&-> decltype(std::declval< Yes >()(std::declval< Value && >())) |
|
template<class Value, class Error>
class folly::Expected< Value, Error >
Expected - For holding a value or an error. Useful as an alternative to exceptions, for APIs where throwing on failure would be too expensive.
Expected<Value, Error> is a variant over the types Value and Error.
Expected does not offer support for references. Use Expected<std::reference_wrapper<T>, Error> if your API needs to return a reference or an error.
Expected offers a continuation-based interface to reduce the boilerplate of checking error codes. The Expected::then member function takes a lambda that is to execute should the Expected object contain a value. The return value of the lambda is wrapped in an Expected and returned. If the lambda is not executed because the Expected contains an error, the error is returned immediately in a new Expected object.
Expected<int, Error> funcTheFirst(); Expected<std::string, Error> funcTheSecond() { return funcTheFirst().then([](int i) { return std::to_string(i); }); }
The above line of code could more verbosely written as:
Expected<std::string, Error> funcTheSecond() { if (auto ex = funcTheFirst()) { return std::to_string(*ex); } return makeUnexpected(ex.error()); }
Continuations can chain, like:
Expected<D, Error> maybeD = someFunc() .then([](A a){return B(a);}) .then([](B b){return C(b);}) .then([](C c){return D(c);});
To avoid the redundant error checking that would happen if a call at the front of the chain returns an error, these call chains can be collaped into a single call to .then:
Expected<D, Error> maybeD = someFunc() .then([](A a){return B(a);}, [](B b){return C(b);}, [](C c){return D(c);});
The result of .then() is wrapped into Expected< ~, Error > if it isn't of that form already. Consider the following code:
extern Expected<std::string, Error> readLineFromIO(); extern Expected<int, Error> parseInt(std::string); extern int increment(int);
Expected<int, Error> x = readLineFromIO().then(parseInt).then(increment);
From the code above, we see that .then() works both with functions that return an Expected< ~, Error > (like parseInt) and with ones that return a plain value (like increment). In the case of parseInt, .then() returns the result of parseInt as-is. In the case of increment, it wraps the int that increment returns into an Expected< int, Error >.
Sometimes when using a continuation you would prefer an exception to be thrown for a value-less Expected. For that you can use .thenOrThrow, as follows:
B b = someFunc() .thenOrThrow([](A a){return B(a);});
The above call to thenOrThrow will invoke the lambda if the Expected returned by someFunc() contains a value. Otherwise, it will throw an exception of type Unexpected<Error>::BadExpectedAccess. If you prefer it throw an exception of a different type, you can pass a second lambda to thenOrThrow:
B b = someFunc() .thenOrThrow([](A a){return B(a);}, [](Error e) {throw MyException(e);});
Like C++17's std::variant, Expected offers the almost-never-empty guarantee; that is, an Expected<Value, Error> almost always contains either a Value or and Error. Partially-formed Expected objects occur when an assignment to an Expected object that would change the type of the contained object (Value- to-Error or vice versa) throws. Trying to access either the contained value or error object causes Expected to throw folly::BadExpectedAccess.
Expected models OptionalPointee, so calling 'get_pointer(ex)' will return a pointer to nullptr if the 'ex' is in the error state, and a pointer to the value otherwise:
Expected<int, Error> maybeInt = ...; if (int* v = get_pointer(maybeInt)) { cout << *v << endl; }
Definition at line 78 of file Expected.h.