forked from TartanLlama/expected
Initial void support
This commit is contained in:
@@ -127,8 +127,8 @@ TEST_CASE("Deletion", "[bases.deletion]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -142,8 +142,8 @@ TEST_CASE("Deletion", "[bases.deletion]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -157,8 +157,8 @@ TEST_CASE("Deletion", "[bases.deletion]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -172,8 +172,8 @@ TEST_CASE("Deletion", "[bases.deletion]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
|
@@ -68,8 +68,8 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -83,8 +83,8 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -98,8 +98,8 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
@@ -113,8 +113,8 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::is_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
|
||||
REQUIRE(std::is_move_assignable<decltype(e)>::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e)));
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
REQUIRE(!IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
# if !defined(TL_EXPECTED_GCC49)
|
||||
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
|
@@ -72,7 +72,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = e.map(ret_void);
|
||||
REQUIRE(ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -80,7 +80,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = e.map(ret_void);
|
||||
REQUIRE(ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -88,7 +88,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
REQUIRE(ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -96,7 +96,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
REQUIRE(ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -104,7 +104,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = e.map(ret_void);
|
||||
REQUIRE(!ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -112,7 +112,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = e.map(ret_void);
|
||||
REQUIRE(!ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -120,7 +120,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
REQUIRE(!ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -128,7 +128,7 @@ TEST_CASE("Map extensions", "[extensions.map]") {
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
REQUIRE(!ret);
|
||||
STATIC_REQUIRE(
|
||||
(std::is_same<decltype(ret), tl::expected<tl::monostate, int>>::value));
|
||||
(std::is_same<decltype(ret), tl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
|
||||
|
271
tl/expected.hpp
271
tl/expected.hpp
@@ -49,22 +49,22 @@
|
||||
// GCC < 5 doesn't support some standard C++11 type traits
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
|
||||
std::has_trivial_copy_constructor<T>::value
|
||||
std::has_trivial_copy_constructor<T>
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value
|
||||
#define IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>
|
||||
|
||||
// This one will be different for GCC 5.7 if it's ever supported
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
|
||||
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
|
||||
#else
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
|
||||
std::is_trivially_copy_constructible<T>::value
|
||||
std::is_trivially_copy_constructible<T>
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
|
||||
std::is_trivially_copy_assignable<T>::value
|
||||
std::is_trivially_copy_assignable<T>
|
||||
/// \exclude
|
||||
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
|
||||
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
|
||||
#endif
|
||||
|
||||
#if __cplusplus > 201103L
|
||||
@@ -166,7 +166,8 @@ constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
/// *Example:*
|
||||
/// auto e1 = tl::make_unexpected(42);
|
||||
/// unexpected<int> e2 (42); //same semantics
|
||||
template <class E> unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
|
||||
template <class E>
|
||||
unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
|
||||
return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
|
||||
}
|
||||
|
||||
@@ -260,11 +261,21 @@ using expected_enable_from_other = detail::enable_if_t<
|
||||
!std::is_convertible<const expected<U, G> &, T>::value &&
|
||||
!std::is_convertible<const expected<U, G> &&, T>::value>;
|
||||
|
||||
template <class T, class U>
|
||||
using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
|
||||
|
||||
template <class T>
|
||||
using is_copy_constructible_or_void = is_void_or<T,std::is_copy_constructible<T>>;
|
||||
|
||||
template <class T>
|
||||
using is_move_constructible_or_void = is_void_or<T,std::is_move_constructible<T>>;
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \exclude
|
||||
namespace detail {
|
||||
struct no_init_t{};
|
||||
struct no_init_t {};
|
||||
static constexpr no_init_t no_init{};
|
||||
|
||||
// Implements the storage of the values, and ensures that the destructor is
|
||||
@@ -446,17 +457,77 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||
};
|
||||
};
|
||||
|
||||
// `T` is `void`, `E` is trivially-destructible
|
||||
template <class E> struct expected_storage_base<void, E, false, true> {
|
||||
constexpr expected_storage_base() : m_has_val(true) {}
|
||||
constexpr expected_storage_base(no_init_t) : m_has_val(false) {}
|
||||
|
||||
constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
|
||||
|
||||
template <class... Args,
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&... args)
|
||||
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&... args)
|
||||
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
~expected_storage_base() = default;
|
||||
bool m_has_val;
|
||||
struct dummy {};
|
||||
union {
|
||||
dummy m_val;
|
||||
unexpected<E> m_unexpect;
|
||||
};
|
||||
};
|
||||
|
||||
// `T` is `void`, `E` is not trivially-destructible
|
||||
template <class E> struct expected_storage_base<void, E, false, false> {
|
||||
constexpr expected_storage_base() : m_has_val(true) {}
|
||||
constexpr expected_storage_base(no_init_t) : m_has_val(false) {}
|
||||
|
||||
constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
|
||||
|
||||
template <class... Args,
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&... args)
|
||||
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&... args)
|
||||
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
~expected_storage_base() {
|
||||
if (!m_has_val) {
|
||||
m_unexpect.~unexpected<E>();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_has_val;
|
||||
struct dummy {};
|
||||
union {
|
||||
dummy m_val;
|
||||
unexpected<E> m_unexpect;
|
||||
};
|
||||
};
|
||||
|
||||
// This base class provides some handy member functions which can be used in
|
||||
// further derived classes
|
||||
template <class T, class E>
|
||||
struct expected_operations_base : expected_storage_base<T, E> {
|
||||
using expected_storage_base<T, E>::expected_storage_base;
|
||||
|
||||
void hard_reset() noexcept {
|
||||
get().~T();
|
||||
this->m_has_val = false;
|
||||
}
|
||||
|
||||
template <class... Args> void construct(Args &&... args) noexcept {
|
||||
new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
|
||||
this->m_has_val = true;
|
||||
@@ -597,9 +668,60 @@ struct expected_operations_base : expected_storage_base<T, E> {
|
||||
#endif
|
||||
};
|
||||
|
||||
// This base class provides some handy member functions which can be used in
|
||||
// further derived classes
|
||||
template <class E>
|
||||
struct expected_operations_base<void,E> : expected_storage_base<void, E> {
|
||||
using expected_storage_base<void, E>::expected_storage_base;
|
||||
|
||||
template <class... Args> void construct() noexcept {
|
||||
this->m_has_val = true;
|
||||
}
|
||||
|
||||
template <class... Args> void construct_error(Args &&... args) noexcept {
|
||||
new (std::addressof(this->m_unexpect))
|
||||
unexpected<E>(std::forward<Args>(args)...);
|
||||
this->m_has_val = false;
|
||||
}
|
||||
|
||||
template <class Rhs>
|
||||
void assign(Rhs &&rhs) noexcept {
|
||||
if (!this->m_has_val) {
|
||||
if (rhs.m_has_val) {
|
||||
geterr().~unexpected<E>();
|
||||
construct();
|
||||
}
|
||||
else {
|
||||
geterr() = std::forward<Rhs>(rhs).geterr();
|
||||
}
|
||||
} else {
|
||||
if (!rhs.m_has_val) {
|
||||
construct_error(std::forward<Rhs>(rhs).geterr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_value() const { return this->m_has_val; }
|
||||
|
||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
|
||||
return this->m_unexpect;
|
||||
}
|
||||
constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
|
||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
|
||||
std::move(this->m_unexpect);
|
||||
}
|
||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||
constexpr const unexpected<E> &&geterr() const && {
|
||||
return std::move(this->m_unexpect);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// This class manages conditionally having a trivial copy constructor
|
||||
// This specialization is for when T and E are trivially copy constructible
|
||||
template <class T, class E, bool = IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) && IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)>
|
||||
template <class T, class E,
|
||||
bool = is_void_or<T,IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::value &&
|
||||
IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
|
||||
struct expected_copy_base : expected_operations_base<T, E> {
|
||||
using expected_operations_base<T, E>::expected_operations_base;
|
||||
};
|
||||
@@ -610,8 +732,8 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||
using expected_operations_base<T, E>::expected_operations_base;
|
||||
|
||||
expected_copy_base() = default;
|
||||
expected_copy_base(const expected_copy_base &rhs) :
|
||||
expected_operations_base<T,E>(no_init) {
|
||||
expected_copy_base(const expected_copy_base &rhs)
|
||||
: expected_operations_base<T, E>(no_init) {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(rhs.get());
|
||||
} else {
|
||||
@@ -631,8 +753,8 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||
// move constructible
|
||||
#ifndef TL_EXPECTED_GCC49
|
||||
template <class T, class E,
|
||||
bool = std::is_trivially_move_constructible<T>::value
|
||||
&& std::is_trivially_move_constructible<E>::value>
|
||||
bool = is_void_or<T,std::is_trivially_move_constructible<T>>::value
|
||||
&&std::is_trivially_move_constructible<E>::value>
|
||||
struct expected_move_base : expected_copy_base<T, E> {
|
||||
using expected_copy_base<T, E>::expected_copy_base;
|
||||
};
|
||||
@@ -647,8 +769,8 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||
expected_move_base(const expected_move_base &rhs) = default;
|
||||
|
||||
expected_move_base(expected_move_base &&rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<T>::value) :
|
||||
expected_copy_base<T,E>(no_init) {
|
||||
std::is_nothrow_move_constructible<T>::value)
|
||||
: expected_copy_base<T, E>(no_init) {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(std::move(rhs.get()));
|
||||
} else {
|
||||
@@ -660,13 +782,14 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||
};
|
||||
|
||||
// This class manages conditionally having a trivial copy assignment operator
|
||||
template <class T, class E,
|
||||
bool = IS_TRIVIALLY_COPY_ASSIGNABLE(T) &&
|
||||
IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) &&
|
||||
IS_TRIVIALLY_DESTRUCTIBLE(T) &&
|
||||
IS_TRIVIALLY_COPY_ASSIGNABLE(E) &&
|
||||
IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E) &&
|
||||
IS_TRIVIALLY_DESTRUCTIBLE(E)>
|
||||
template <
|
||||
class T, class E,
|
||||
bool = is_void_or<T,
|
||||
conjunction<IS_TRIVIALLY_COPY_ASSIGNABLE(T),
|
||||
IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
|
||||
IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&
|
||||
IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&
|
||||
IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value && IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
|
||||
struct expected_copy_assign_base : expected_move_base<T, E> {
|
||||
using expected_move_base<T, E>::expected_move_base;
|
||||
};
|
||||
@@ -694,9 +817,10 @@ struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
|
||||
// move assignable
|
||||
#ifndef TL_EXPECTED_GCC49
|
||||
template <class T, class E,
|
||||
bool = std::is_trivially_destructible<T>::value
|
||||
&&std::is_trivially_move_constructible<T>::value
|
||||
&&std::is_trivially_move_assignable<T>::value
|
||||
bool =
|
||||
is_void_or<T, conjunction<std::is_trivially_destructible<T>,
|
||||
std::is_trivially_move_constructible<T>,
|
||||
std::is_trivially_move_assignable<T>>>::value
|
||||
&&std::is_trivially_destructible<E>::value
|
||||
&&std::is_trivially_move_constructible<E>::value
|
||||
&&std::is_trivially_move_assignable<E>::value>
|
||||
@@ -724,7 +848,7 @@ struct expected_move_assign_base<T, E, false>
|
||||
operator=(expected_move_assign_base &&rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<T>::value
|
||||
&&std::is_nothrow_move_assignable<T>::value) {
|
||||
this->assign(std::move(rhs));
|
||||
this->assign(std::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@@ -732,9 +856,9 @@ struct expected_move_assign_base<T, E, false>
|
||||
// expected_delete_ctor_base will conditionally delete copy and move
|
||||
// constructors depending on whether T is copy/move constructible
|
||||
template <class T, class E,
|
||||
bool EnableCopy = (std::is_copy_constructible<T>::value &&
|
||||
bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
|
||||
std::is_copy_constructible<E>::value),
|
||||
bool EnableMove = (std::is_move_constructible<T>::value &&
|
||||
bool EnableMove = (is_move_constructible_or_void<T>::value &&
|
||||
std::is_move_constructible<E>::value)>
|
||||
struct expected_delete_ctor_base {
|
||||
expected_delete_ctor_base() = default;
|
||||
@@ -848,7 +972,7 @@ struct default_constructor_tag {
|
||||
// consturctor if T is not default constructible.
|
||||
// This specialization is for when T is default constructible
|
||||
template <class T, class E,
|
||||
bool Enable = std::is_default_constructible<T>::value>
|
||||
bool Enable = std::is_default_constructible<T>::value || std::is_void<T>::value>
|
||||
struct expected_default_ctor_base {
|
||||
constexpr expected_default_ctor_base() noexcept = default;
|
||||
constexpr expected_default_ctor_base(
|
||||
@@ -916,13 +1040,16 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
||||
static_assert(!std::is_same<T, std::remove_cv<unexpected<E>>>::value,
|
||||
"T must not be unexpected<E>");
|
||||
static_assert(!std::is_reference<E>::value, "E must not be a reference");
|
||||
static_assert(!std::is_same<T, void>::value, "T must not be void");
|
||||
|
||||
T *valptr() { return std::addressof(this->m_val); }
|
||||
unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
|
||||
T &val() { return this->m_val; }
|
||||
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
U &val() { return this->m_val; }
|
||||
unexpected<E> &err() { return this->m_unexpect; }
|
||||
const T &val() const { return this->m_val; }
|
||||
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
const U &val() const { return this->m_val; }
|
||||
const unexpected<E> &err() const { return this->m_unexpect; }
|
||||
|
||||
using impl_base = detail::expected_move_assign_base<T, E>;
|
||||
@@ -1387,15 +1514,17 @@ public:
|
||||
|
||||
template <
|
||||
class U = T,
|
||||
detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
|
||||
nullptr,
|
||||
detail::enable_if_t<!std::is_void<U>::value>* = nullptr,
|
||||
detail::enable_if_t<
|
||||
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
||||
!detail::conjunction<std::is_scalar<T>,
|
||||
std::is_same<T, detail::decay_t<U>>>::value &&
|
||||
std::is_constructible<T, U>::value &&
|
||||
std::is_assignable<T &, U>::value &&
|
||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr,
|
||||
detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
|
||||
nullptr>
|
||||
// std::is_assignable<T &, U>::value &&
|
||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
||||
>
|
||||
expected &operator=(U &&v) {
|
||||
if (has_value()) {
|
||||
val() = std::forward<U>(v);
|
||||
@@ -1411,15 +1540,17 @@ public:
|
||||
/// \exclude
|
||||
template <
|
||||
class U = T,
|
||||
detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
|
||||
nullptr,
|
||||
detail::enable_if_t<!std::is_void<U>::value>* = nullptr,
|
||||
detail::enable_if_t<
|
||||
(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
|
||||
!detail::conjunction<std::is_scalar<T>,
|
||||
std::is_same<T, detail::decay_t<U>>>::value &&
|
||||
std::is_constructible<T, U>::value &&
|
||||
std::is_assignable<T &, U>::value &&
|
||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr,
|
||||
detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
|
||||
nullptr>
|
||||
// std::is_assignable<T &, U>::value &&
|
||||
std::is_nothrow_move_constructible<E>::value)> * = nullptr
|
||||
>
|
||||
expected &operator=(U &&v) {
|
||||
if (has_value()) {
|
||||
val() = std::forward<U>(v);
|
||||
@@ -1571,13 +1702,17 @@ public:
|
||||
/// \returns the stored value
|
||||
/// \requires a value is stored
|
||||
/// \group deref
|
||||
constexpr const T &operator*() const & { return val(); }
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
constexpr const U &operator*() const & { return val(); }
|
||||
/// \group deref
|
||||
TL_EXPECTED_11_CONSTEXPR T &operator*() & { return val(); }
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_11_CONSTEXPR U &operator*() & { return val(); }
|
||||
/// \group deref
|
||||
constexpr const T &&operator*() const && { return std::move(val()); }
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
constexpr const U &&operator*() const && { return std::move(val()); }
|
||||
/// \group deref
|
||||
TL_EXPECTED_11_CONSTEXPR T &&operator*() && { return std::move(val()); }
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_11_CONSTEXPR U &&operator*() && { return std::move(val()); }
|
||||
|
||||
/// \returns whether or not the optional has a value
|
||||
/// \group has_value
|
||||
@@ -1585,28 +1720,33 @@ public:
|
||||
/// \group has_value
|
||||
constexpr explicit operator bool() const noexcept { return this->m_has_val; }
|
||||
|
||||
|
||||
/// \returns the contained value if there is one, otherwise throws [bad_expected_access]
|
||||
/// \returns the contained value if there is one, otherwise throws
|
||||
/// [bad_expected_access]
|
||||
///
|
||||
/// \group value
|
||||
TL_EXPECTED_GCC49_CONSTEXPR const T &value() const & {
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_GCC49_CONSTEXPR const U &value() const & {
|
||||
if (!has_value())
|
||||
throw bad_expected_access<E>(err().value());
|
||||
return val();
|
||||
}
|
||||
/// \group value
|
||||
TL_EXPECTED_11_CONSTEXPR T &value() & {
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_11_CONSTEXPR U &value() & {
|
||||
if (!has_value())
|
||||
throw bad_expected_access<E>(err().value());
|
||||
return val();
|
||||
}
|
||||
/// \group value
|
||||
TL_EXPECTED_GCC49_CONSTEXPR const T &&value() const && {
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_GCC49_CONSTEXPR const U &&value() const && {
|
||||
if (!has_value())
|
||||
throw bad_expected_access<E>(err().value());
|
||||
return std::move(val());
|
||||
}
|
||||
/// \group value
|
||||
TL_EXPECTED_11_CONSTEXPR T &&value() && {
|
||||
template <class U=T, detail::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||
TL_EXPECTED_11_CONSTEXPR U &&value() && {
|
||||
if (!has_value())
|
||||
throw bad_expected_access<E>(err().value());
|
||||
return std::move(val());
|
||||
@@ -1663,10 +1803,10 @@ template <class Exp, class F,
|
||||
*std::declval<Exp>())),
|
||||
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||
auto map_impl(Exp &&exp, F &&f) {
|
||||
using result = expected<monostate, err_t<Exp>>;
|
||||
using result = expected<void, err_t<Exp>>;
|
||||
if (exp.has_value()) {
|
||||
detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
|
||||
return result(monostate{});
|
||||
return result();
|
||||
}
|
||||
|
||||
return result(unexpect, std::forward<Exp>(exp).error());
|
||||
@@ -1690,10 +1830,10 @@ template <class Exp, class F,
|
||||
*std::declval<Exp>())),
|
||||
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||
|
||||
auto map_impl(Exp &&exp, F &&f) -> expected<monostate, err_t<Exp>> {
|
||||
auto map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
|
||||
if (exp.has_value()) {
|
||||
detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
|
||||
return tl::monostate{};
|
||||
return {};
|
||||
}
|
||||
|
||||
return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
|
||||
@@ -1720,11 +1860,10 @@ template <class Exp, class F,
|
||||
auto map_error_impl(Exp &&exp, F &&f) {
|
||||
using result = expected<exp_t<Exp>, monostate>;
|
||||
if (exp.has_value()) {
|
||||
return result(*std::forward<Exp>(exp));
|
||||
return result(*std::forward<Exp>(exp));
|
||||
}
|
||||
|
||||
detail::invoke(std::forward<F>(f),
|
||||
std::forward<Exp>(exp).error());
|
||||
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||
return result(unexpect, monostate{});
|
||||
}
|
||||
#else
|
||||
@@ -1732,7 +1871,8 @@ template <class Exp, class F,
|
||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||
*std::declval<Exp>())),
|
||||
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
||||
constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
|
||||
constexpr auto map_error_impl(Exp &&exp, F &&f)
|
||||
-> expected<exp_t<Exp>, detail::decay_t<Ret>> {
|
||||
using result = ret_t<Exp, detail::decay_t<Ret>>;
|
||||
|
||||
return exp.has_value()
|
||||
@@ -1748,11 +1888,10 @@ template <class Exp, class F,
|
||||
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
|
||||
using result = expected<exp_t<Exp>, monostate>;
|
||||
if (exp.has_value()) {
|
||||
return result(*std::forward<Exp>(exp));
|
||||
return result(*std::forward<Exp>(exp));
|
||||
}
|
||||
|
||||
detail::invoke(std::forward<F>(f),
|
||||
std::forward<Exp>(exp).error());
|
||||
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||
return result(unexpect, monostate{});
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user