mirror of
https://github.com/TartanLlama/expected.git
synced 2025-08-03 10:54:31 +02:00
More void support
This commit is contained in:
@@ -15,6 +15,13 @@ TEST_CASE("Triviality", "[bases.triviality]") {
|
|||||||
REQUIRE(std::is_trivially_move_assignable<tl::expected<int,int>>::value);
|
REQUIRE(std::is_trivially_move_assignable<tl::expected<int,int>>::value);
|
||||||
REQUIRE(std::is_trivially_destructible<tl::expected<int,int>>::value);
|
REQUIRE(std::is_trivially_destructible<tl::expected<int,int>>::value);
|
||||||
|
|
||||||
|
REQUIRE(std::is_trivially_copy_constructible<tl::expected<void,int>>::value);
|
||||||
|
REQUIRE(std::is_trivially_copy_assignable<tl::expected<void,int>>::value);
|
||||||
|
REQUIRE(std::is_trivially_move_constructible<tl::expected<void,int>>::value);
|
||||||
|
REQUIRE(std::is_trivially_move_assignable<tl::expected<void,int>>::value);
|
||||||
|
REQUIRE(std::is_trivially_destructible<tl::expected<void,int>>::value);
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
struct T {
|
struct T {
|
||||||
T(const T&) = default;
|
T(const T&) = default;
|
||||||
|
@@ -120,4 +120,15 @@ TEST_CASE("Constructors", "[constructors]") {
|
|||||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<void,int> e;
|
||||||
|
REQUIRE(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<void,int> e (tl::unexpect, 42);
|
||||||
|
REQUIRE(!e);
|
||||||
|
REQUIRE(e.error() == 42);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
176
tl/expected.hpp
176
tl/expected.hpp
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -266,11 +265,11 @@ using expected_enable_from_other = detail::enable_if_t<
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
using is_copy_constructible_or_void = is_void_or<T,std::is_copy_constructible<T>>;
|
using is_copy_constructible_or_void = is_void_or<T,std::is_copy_constructible<T>>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
using is_move_constructible_or_void = is_void_or<T,std::is_move_constructible<T>>;
|
using is_move_constructible_or_void = is_void_or<T,std::is_move_constructible<T>>;
|
||||||
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
@@ -528,10 +527,16 @@ template <class T, class E>
|
|||||||
struct expected_operations_base : expected_storage_base<T, E> {
|
struct expected_operations_base : expected_storage_base<T, E> {
|
||||||
using expected_storage_base<T, E>::expected_storage_base;
|
using expected_storage_base<T, E>::expected_storage_base;
|
||||||
|
|
||||||
template <class... Args> void construct(Args &&... args) noexcept {
|
template <class... Args> void construct(Args &&... args) noexcept {
|
||||||
new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
|
new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
|
||||||
this->m_has_val = true;
|
this->m_has_val = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Rhs>
|
||||||
|
void construct_with(Rhs && rhs) noexcept {
|
||||||
|
new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
template <class... Args> void construct_error(Args &&... args) noexcept {
|
template <class... Args> void construct_error(Args &&... args) noexcept {
|
||||||
new (std::addressof(this->m_unexpect))
|
new (std::addressof(this->m_unexpect))
|
||||||
@@ -678,6 +683,12 @@ struct expected_operations_base<void,E> : expected_storage_base<void, E> {
|
|||||||
this->m_has_val = true;
|
this->m_has_val = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Rhs>
|
||||||
|
void construct_with(Rhs && rhs) noexcept {
|
||||||
|
this->m_has_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class... Args> void construct_error(Args &&... args) noexcept {
|
template <class... Args> void construct_error(Args &&... args) noexcept {
|
||||||
new (std::addressof(this->m_unexpect))
|
new (std::addressof(this->m_unexpect))
|
||||||
unexpected<E>(std::forward<Args>(args)...);
|
unexpected<E>(std::forward<Args>(args)...);
|
||||||
@@ -700,7 +711,7 @@ struct expected_operations_base<void,E> : expected_storage_base<void, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_value() const { return this->m_has_val; }
|
bool has_value() const { return this->m_has_val; }
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
|
||||||
@@ -716,7 +727,7 @@ struct expected_operations_base<void,E> : expected_storage_base<void, E> {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class manages conditionally having a trivial copy constructor
|
// This class manages conditionally having a trivial copy constructor
|
||||||
// This specialization is for when T and E are trivially copy constructible
|
// This specialization is for when T and E are trivially copy constructible
|
||||||
template <class T, class E,
|
template <class T, class E,
|
||||||
@@ -735,7 +746,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
|||||||
expected_copy_base(const expected_copy_base &rhs)
|
expected_copy_base(const expected_copy_base &rhs)
|
||||||
: expected_operations_base<T, E>(no_init) {
|
: expected_operations_base<T, E>(no_init) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->construct(rhs.get());
|
this->construct_with(rhs);
|
||||||
} else {
|
} else {
|
||||||
this->construct_error(rhs.geterr());
|
this->construct_error(rhs.geterr());
|
||||||
}
|
}
|
||||||
@@ -772,7 +783,7 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
|||||||
std::is_nothrow_move_constructible<T>::value)
|
std::is_nothrow_move_constructible<T>::value)
|
||||||
: expected_copy_base<T, E>(no_init) {
|
: expected_copy_base<T, E>(no_init) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->construct(std::move(rhs.get()));
|
this->construct_with(std::move(rhs));
|
||||||
} else {
|
} else {
|
||||||
this->construct_error(std::move(rhs.geterr()));
|
this->construct_error(std::move(rhs.geterr()));
|
||||||
}
|
}
|
||||||
@@ -1048,7 +1059,7 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
|||||||
U &val() { return this->m_val; }
|
U &val() { return this->m_val; }
|
||||||
unexpected<E> &err() { return this->m_unexpect; }
|
unexpected<E> &err() { return this->m_unexpect; }
|
||||||
|
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
const U &val() const { return this->m_val; }
|
const U &val() const { return this->m_val; }
|
||||||
const unexpected<E> &err() const { return this->m_unexpect; }
|
const unexpected<E> &err() const { return this->m_unexpect; }
|
||||||
|
|
||||||
@@ -1072,46 +1083,26 @@ public:
|
|||||||
/// is returned.
|
/// is returned.
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
|
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
|
||||||
using result = detail::invoke_result_t<F, T &>;
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, this->error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
|
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
|
||||||
using result = detail::invoke_result_t<F, T &&>;
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
||||||
: result(unexpect, std::move(this->error()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||||
template <class F> constexpr auto and_then(F &&f) const & {
|
template <class F> constexpr auto and_then(F &&f) const & {
|
||||||
using result = detail::invoke_result_t<F, const T &>;
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, this->error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||||
template <class F> constexpr auto and_then(F &&f) const && {
|
template <class F> constexpr auto and_then(F &&f) const && {
|
||||||
using result = detail::invoke_result_t<F, const T &&>;
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
||||||
: result(unexpect, std::move(this->error()));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1126,50 +1117,30 @@ public:
|
|||||||
/// is returned.
|
/// is returned.
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||||
template <class F>
|
template <class F>
|
||||||
TL_EXPECTED_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) & {
|
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(*this, std::forward<F>(f))) {
|
||||||
using result = detail::invoke_result_t<F, T &>;
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, this->error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
TL_EXPECTED_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && {
|
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(std::move(*this), std::forward<F>(f))) {
|
||||||
using result = detail::invoke_result_t<F, T &&>;
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, std::move(this->error()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||||
template <class F>
|
template <class F>
|
||||||
constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & {
|
constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(*this, std::forward<F>(f))) {
|
||||||
using result = detail::invoke_result_t<F, const T &>;
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, this->error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
constexpr detail::invoke_result_t<F, const T &&> and_then(F &&f) const && {
|
constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(std::move(*this), std::forward<F>(f))) {
|
||||||
using result = detail::invoke_result_t<F, const T &&>;
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
static_assert(detail::is_expected<result>::value,
|
|
||||||
"F must return an expected");
|
|
||||||
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(unexpect, std::move(this->error()));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -1514,15 +1485,16 @@ public:
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
class U = T,
|
class U = T,
|
||||||
|
class G = T,
|
||||||
detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
|
detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
|
||||||
nullptr,
|
nullptr,
|
||||||
detail::enable_if_t<!std::is_void<U>::value>* = nullptr,
|
detail::enable_if_t<!std::is_void<G>::value>* = nullptr,
|
||||||
detail::enable_if_t<
|
detail::enable_if_t<
|
||||||
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
||||||
!detail::conjunction<std::is_scalar<T>,
|
!detail::conjunction<std::is_scalar<T>,
|
||||||
std::is_same<T, detail::decay_t<U>>>::value &&
|
std::is_same<T, detail::decay_t<U>>>::value &&
|
||||||
std::is_constructible<T, U>::value &&
|
std::is_constructible<T, U>::value &&
|
||||||
// std::is_assignable<T &, U>::value &&
|
std::is_assignable<G &, U>::value &&
|
||||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
||||||
>
|
>
|
||||||
expected &operator=(U &&v) {
|
expected &operator=(U &&v) {
|
||||||
@@ -1540,15 +1512,16 @@ public:
|
|||||||
/// \exclude
|
/// \exclude
|
||||||
template <
|
template <
|
||||||
class U = T,
|
class U = T,
|
||||||
|
class G = T,
|
||||||
detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
|
detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
|
||||||
nullptr,
|
nullptr,
|
||||||
detail::enable_if_t<!std::is_void<U>::value>* = nullptr,
|
detail::enable_if_t<!std::is_void<U>::value>* = nullptr,
|
||||||
detail::enable_if_t<
|
detail::enable_if_t<
|
||||||
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
||||||
!detail::conjunction<std::is_scalar<T>,
|
!detail::conjunction<std::is_scalar<T>,
|
||||||
std::is_same<T, detail::decay_t<U>>>::value &&
|
std::is_same<T, detail::decay_t<U>>>::value &&
|
||||||
std::is_constructible<T, U>::value &&
|
std::is_constructible<T, U>::value &&
|
||||||
// std::is_assignable<T &, U>::value &&
|
std::is_assignable<G &, U>::value &&
|
||||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
||||||
>
|
>
|
||||||
expected &operator=(U &&v) {
|
expected &operator=(U &&v) {
|
||||||
@@ -1705,13 +1678,13 @@ public:
|
|||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
constexpr const U &operator*() const & { return val(); }
|
constexpr const U &operator*() const & { return val(); }
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_11_CONSTEXPR U &operator*() & { return val(); }
|
TL_EXPECTED_11_CONSTEXPR U &operator*() & { return val(); }
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
constexpr const U &&operator*() const && { return std::move(val()); }
|
constexpr const U &&operator*() const && { return std::move(val()); }
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_11_CONSTEXPR U &&operator*() && { return std::move(val()); }
|
TL_EXPECTED_11_CONSTEXPR U &&operator*() && { return std::move(val()); }
|
||||||
|
|
||||||
/// \returns whether or not the optional has a value
|
/// \returns whether or not the optional has a value
|
||||||
@@ -1724,28 +1697,28 @@ public:
|
|||||||
/// [bad_expected_access]
|
/// [bad_expected_access]
|
||||||
///
|
///
|
||||||
/// \group value
|
/// \group value
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_GCC49_CONSTEXPR const U &value() const & {
|
TL_EXPECTED_GCC49_CONSTEXPR const U &value() const & {
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
throw bad_expected_access<E>(err().value());
|
throw bad_expected_access<E>(err().value());
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
/// \group value
|
/// \group value
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_11_CONSTEXPR U &value() & {
|
TL_EXPECTED_11_CONSTEXPR U &value() & {
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
throw bad_expected_access<E>(err().value());
|
throw bad_expected_access<E>(err().value());
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
/// \group value
|
/// \group value
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_GCC49_CONSTEXPR const U &&value() const && {
|
TL_EXPECTED_GCC49_CONSTEXPR const U &&value() const && {
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
throw bad_expected_access<E>(err().value());
|
throw bad_expected_access<E>(err().value());
|
||||||
return std::move(val());
|
return std::move(val());
|
||||||
}
|
}
|
||||||
/// \group value
|
/// \group value
|
||||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
TL_EXPECTED_11_CONSTEXPR U &&value() && {
|
TL_EXPECTED_11_CONSTEXPR U &&value() && {
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
throw bad_expected_access<E>(err().value());
|
throw bad_expected_access<E>(err().value());
|
||||||
@@ -1782,10 +1755,61 @@ public:
|
|||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <class Exp> using exp_t = typename detail::decay_t<Exp>::error_type;
|
template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
|
||||||
template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
|
template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
|
||||||
template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
|
template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
|
||||||
|
|
||||||
|
#ifdef TL_EXPECTED_CXX14
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Exp>())),
|
||||||
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
|
||||||
|
constexpr auto and_then_impl(Exp &&exp, F &&f) {
|
||||||
|
static_assert(detail::is_expected<Ret>::value,
|
||||||
|
"F must return an expected");
|
||||||
|
|
||||||
|
return exp.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
||||||
|
: Ret(unexpect, exp.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Exp>())),
|
||||||
|
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
|
||||||
|
constexpr auto and_then_impl(Exp &&exp, F &&f) {
|
||||||
|
static_assert(detail::is_expected<Ret>::value,
|
||||||
|
"F must return an expected");
|
||||||
|
|
||||||
|
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
||||||
|
: Ret(unexpect, exp.error());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<class>struct TC;
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Exp>())),
|
||||||
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
|
||||||
|
auto and_then_impl(Exp &&exp, F &&f) -> Ret {
|
||||||
|
static_assert(detail::is_expected<Ret>::value,
|
||||||
|
"F must return an expected");
|
||||||
|
|
||||||
|
return exp.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
||||||
|
: Ret(unexpect, exp.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Exp>())),
|
||||||
|
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
|
||||||
|
constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
|
||||||
|
static_assert(detail::is_expected<Ret>::value,
|
||||||
|
"F must return an expected");
|
||||||
|
|
||||||
|
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
||||||
|
: Ret(unexpect, exp.error());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TL_EXPECTED_CXX14
|
#ifdef TL_EXPECTED_CXX14
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
Reference in New Issue
Block a user