///
// expected - An implementation of std::expected with extensions
-// Written in 2017 by Simon Brand (@TartanLlama)
+// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
+//
+// Documentation available at http://tl.tartanllama.xyz/
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
#ifndef TL_EXPECTED_HPP
#define TL_EXPECTED_HPP
-#define TL_EXPECTED_VERSION_MAJOR 0
-#define TL_EXPECTED_VERSION_MINOR 2
+#define TL_EXPECTED_VERSION_MAJOR 1
+#define TL_EXPECTED_VERSION_MINOR 0
+#define TL_EXPECTED_VERSION_PATCH 1
#include <exception>
#include <functional>
#endif
#if (defined(_MSC_VER) && _MSC_VER == 1900)
-/// \exclude
#define TL_EXPECTED_MSVC2015
#define TL_EXPECTED_MSVC2015_CONSTEXPR
#else
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
-/// \exclude
#define TL_EXPECTED_GCC49
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
!defined(__clang__))
-/// \exclude
#define TL_EXPECTED_GCC54
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
!defined(__clang__))
-/// \exclude
#define TL_EXPECTED_GCC55
#endif
+#if !defined(TL_ASSERT)
+//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
+#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
+#include <cassert>
+#define TL_ASSERT(x) assert(x)
+#else
+#define TL_ASSERT(x)
+#endif
+#endif
+
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
// GCC < 5 doesn't support overloading on const&& for member functions
-/// \exclude
-#define TL_EXPECTED_NO_CONSTRR
+#define TL_EXPECTED_NO_CONSTRR
// GCC < 5 doesn't support some standard C++11 type traits
-/// \exclude
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
std::has_trivial_copy_constructor<T>
-/// \exclude
#define TL_EXPECTED_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 TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
std::is_trivially_destructible<T>
-// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector
-// for non-copyable types
-#elif (defined(__GNUC__) && __GNUC__ < 8 && \
- !defined(__clang__))
+// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
+// std::vector for non-copyable types
+#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
namespace tl {
- namespace detail {
- template<class T>
- struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T>{};
+namespace detail {
+template <class T>
+struct is_trivially_copy_constructible
+ : std::is_trivially_copy_constructible<T> {};
#ifdef _GLIBCXX_VECTOR
- template<class T, class A>
- struct is_trivially_copy_constructible<std::vector<T,A>>
- : std::is_trivially_copy_constructible<T>{};
+template <class T, class A>
+struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
#endif
- }
-}
+} // namespace detail
+} // namespace tl
#endif
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
tl::detail::is_trivially_copy_constructible<T>
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
std::is_trivially_copy_assignable<T>
-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
+#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+ std::is_trivially_destructible<T>
#else
-/// \exclude
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
std::is_trivially_copy_constructible<T>
-/// \exclude
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
std::is_trivially_copy_assignable<T>
-/// \exclude
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
std::is_trivially_destructible<T>
#endif
#if __cplusplus > 201103L
-/// \exclude
#define TL_EXPECTED_CXX14
#endif
#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
defined(TL_EXPECTED_GCC49))
-/// \exclude
#define TL_EXPECTED_11_CONSTEXPR
#else
-/// \exclude
#define TL_EXPECTED_11_CONSTEXPR constexpr
#endif
#ifndef TL_MONOSTATE_INPLACE_MUTEX
#define TL_MONOSTATE_INPLACE_MUTEX
-/// \brief Used to represent an expected with no data
class monostate {};
-/// \brief A tag type to tell expected to construct its value in-place
struct in_place_t {
explicit in_place_t() = default;
};
-/// \brief A tag to tell expected to construct its value in-place
static constexpr in_place_t in_place{};
#endif
-/// Used as a wrapper to store the unexpected value
template <class E> class unexpected {
public:
static_assert(!std::is_same<E, void>::value, "E must not be void");
constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
- /// \returns the contained value
- /// \group unexpected_value
+ template <class... Args, typename std::enable_if<std::is_constructible<
+ E, Args &&...>::value>::type * = nullptr>
+ constexpr explicit unexpected(Args &&...args)
+ : m_val(std::forward<Args>(args)...) {}
+ template <
+ class U, class... Args,
+ typename std::enable_if<std::is_constructible<
+ E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
+ constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
+ : m_val(l, std::forward<Args>(args)...) {}
+
constexpr const E &value() const & { return m_val; }
- /// \group unexpected_value
TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
- /// \group unexpected_value
TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
- /// \exclude
constexpr const E &&value() const && { return std::move(m_val); }
private:
E m_val;
};
-/// \brief Compares two unexpected objects
-/// \details Simply compares lhs.value() to rhs.value()
-/// \group unexpected_relop
+#ifdef __cpp_deduction_guides
+template <class E> unexpected(E) -> unexpected<E>;
+#endif
+
template <class E>
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() == rhs.value();
}
-/// \group unexpected_relop
template <class E>
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() != rhs.value();
}
-/// \group unexpected_relop
template <class E>
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() < rhs.value();
}
-/// \group unexpected_relop
template <class E>
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() <= rhs.value();
}
-/// \group unexpected_relop
template <class E>
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() > rhs.value();
}
-/// \group unexpected_relop
template <class E>
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() >= rhs.value();
}
-/// Create an `unexpected` from `e`, deducing the return type
-///
-/// *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) {
return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
}
-/// \brief A tag type to tell expected to construct the unexpected value
struct unexpect_t {
unexpect_t() = default;
};
-/// \brief A tag to tell expected to construct the unexpected value
static constexpr unexpect_t unexpect{};
-/// \exclude
namespace detail {
-template<typename E>
+template <typename E>
[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- throw std::forward<E>(e);
+ throw std::forward<E>(e);
#else
- #ifdef _MSC_VER
- __assume(0);
- #else
- __builtin_unreachable();
- #endif
+ (void)e;
+#ifdef _MSC_VER
+ __assume(0);
+#else
+ __builtin_unreachable();
+#endif
#endif
}
struct conjunction<B, Bs...>
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
+#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
+#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+#endif
+
+// In C++11 mode, there's an issue in libc++'s std::mem_fn
+// which results in a hard-error when using it in a noexcept expression
+// in some cases. This is a check to workaround the common failing case.
+#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+template <class T>
+struct is_pointer_to_non_const_member_func : std::false_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
+ : std::true_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
+ : std::true_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
+ : std::true_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
+ : std::true_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
+ : std::true_type {};
+template <class T, class Ret, class... Args>
+struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
+ : std::true_type {};
+
+template <class T> struct is_const_or_const_ref : std::false_type {};
+template <class T> struct is_const_or_const_ref<T const &> : std::true_type {};
+template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
+#endif
+
// std::invoke from C++17
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
-template <typename Fn, typename... Args,
- typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>{}>,
- int = 0>
-constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
+template <
+ typename Fn, typename... Args,
+#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+ typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
+ is_const_or_const_ref<Args...>::value)>,
+#endif
+ typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
+constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
return std::mem_fn(f)(std::forward<Args>(args)...);
}
template <typename Fn, typename... Args,
- typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
-constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
+ typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
+constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
return std::forward<Fn>(f)(std::forward<Args>(args)...);
template <class F, class... Us>
struct invoke_result_impl<
- F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
+ F,
+ decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
Us...> {
- using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
+ using type =
+ decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
};
template <class F, class... Us>
template <class F, class... Us>
using invoke_result_t = typename invoke_result<F, Us...>::type;
+
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+// TODO make a version which works with MSVC 2015
+template <class T, class U = T> struct is_swappable : std::true_type {};
+
+template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
+#else
+// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
+namespace swap_adl_tests {
+// if swap ADL finds this then it would call std::swap otherwise (same
+// signature)
+struct tag {};
+
+template <class T> tag swap(T &, T &);
+template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
+
+// helper functions to test if an unqualified swap is possible, and if it
+// becomes std::swap
+template <class, class> std::false_type can_swap(...) noexcept(false);
+template <class T, class U,
+ class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
+std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
+ std::declval<U &>())));
+
+template <class, class> std::false_type uses_std(...);
+template <class T, class U>
+std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
+uses_std(int);
+
+template <class T>
+struct is_std_swap_noexcept
+ : std::integral_constant<bool,
+ std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_assignable<T>::value> {};
+
+template <class T, std::size_t N>
+struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
+
+template <class T, class U>
+struct is_adl_swap_noexcept
+ : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
+} // namespace swap_adl_tests
+
+template <class T, class U = T>
+struct is_swappable
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
+ (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
+ (std::is_move_assignable<T>::value &&
+ std::is_move_constructible<T>::value))> {};
+
+template <class T, std::size_t N>
+struct is_swappable<T[N], T[N]>
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
+ (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
+ 0))::value ||
+ is_swappable<T, T>::value)> {};
+
+template <class T, class U = T>
+struct is_nothrow_swappable
+ : std::integral_constant<
+ bool,
+ is_swappable<T, U>::value &&
+ ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
+ detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
+ (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
+ detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
+#endif
#endif
// Trait for checking if a type is a tl::expected
is_void_or<T, std::is_move_constructible<T>>;
template <class T>
-using is_copy_assignable_or_void =
- is_void_or<T, std::is_copy_assignable<T>>;
-
+using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
template <class T>
-using is_move_assignable_or_void =
- is_void_or<T, std::is_move_assignable<T>>;
-
+using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
} // namespace detail
-/// \exclude
namespace detail {
struct no_init_t {};
static constexpr no_init_t no_init{};
template <class... Args,
detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
nullptr>
- constexpr expected_storage_base(in_place_t, Args &&... args)
+ constexpr expected_storage_base(in_place_t, Args &&...args)
: m_val(std::forward<Args>(args)...), m_has_val(true) {}
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_val(il, std::forward<Args>(args)...), 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)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() {
}
}
union {
- char m_no_init;
T m_val;
unexpected<E> m_unexpect;
+ char m_no_init;
};
bool m_has_val;
};
template <class... Args,
detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
nullptr>
- constexpr expected_storage_base(in_place_t, Args &&... args)
+ constexpr expected_storage_base(in_place_t, Args &&...args)
: m_val(std::forward<Args>(args)...), m_has_val(true) {}
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_val(il, std::forward<Args>(args)...), 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)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() = default;
union {
- char m_no_init;
T m_val;
unexpected<E> m_unexpect;
+ char m_no_init;
};
bool m_has_val;
};
template <class... Args,
detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
nullptr>
- constexpr expected_storage_base(in_place_t, Args &&... args)
+ constexpr expected_storage_base(in_place_t, Args &&...args)
: m_val(std::forward<Args>(args)...), m_has_val(true) {}
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_val(il, std::forward<Args>(args)...), 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)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() {
}
union {
- char m_no_init;
T m_val;
unexpected<E> m_unexpect;
+ char m_no_init;
};
bool m_has_val;
};
template <class... Args,
detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
nullptr>
- constexpr expected_storage_base(in_place_t, Args &&... args)
+ constexpr expected_storage_base(in_place_t, Args &&...args)
: m_val(std::forward<Args>(args)...), m_has_val(true) {}
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_val(il, std::forward<Args>(args)...), 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)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() {
}
}
union {
- char m_no_init;
T m_val;
unexpected<E> m_unexpect;
+ char m_no_init;
};
bool m_has_val;
};
// `T` is `void`, `E` is trivially-destructible
template <class E> struct expected_storage_base<void, E, false, true> {
- TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {}
+ #if __GNUC__ <= 5
+ //no constexpr for GCC 4/5 bug
+ #else
+ TL_EXPECTED_MSVC2015_CONSTEXPR
+ #endif
+ expected_storage_base() : m_has_val(true) {}
+
constexpr expected_storage_base(no_init_t) : m_val(), 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)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() = default;
struct dummy {};
union {
- dummy m_val;
unexpected<E> m_unexpect;
+ dummy m_val;
};
bool m_has_val;
};
template <class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&... args)
+ constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
: m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
template <class U, class... Args,
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected_storage_base(unexpect_t,
std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() {
}
union {
- char m_dummy;
unexpected<E> m_unexpect;
+ char m_dummy;
};
bool m_has_val;
};
struct expected_operations_base : expected_storage_base<T, E> {
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)...);
this->m_has_val = true;
}
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))
unexpected<E>(std::forward<Args>(args)...);
this->m_has_val = false;
}
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
// These assign overloads ensure that the most efficient assignment
// implementation is used while maintaining the strong exception guarantee.
auto tmp = std::move(geterr());
geterr().~unexpected<E>();
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
try {
construct(rhs.get());
} catch (...) {
geterr() = std::move(tmp);
throw;
}
+#else
+ construct(rhs.get());
+#endif
} else {
assign_common(rhs);
}
if (!this->m_has_val && rhs.m_has_val) {
auto tmp = std::move(geterr());
geterr().~unexpected<E>();
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
try {
construct(std::move(rhs).get());
} catch (...) {
geterr() = std::move(tmp);
throw;
}
+#else
+ construct(std::move(rhs).get());
+#endif
} else {
assign_common(std::move(rhs));
}
}
- #else
+#else
// If exceptions are disabled then we can just copy-construct
void assign(const expected_operations_base &rhs) noexcept {
geterr().~unexpected<E>();
construct(std::move(rhs).get());
} else {
- assign_common(rhs);
+ assign_common(std::move(rhs));
}
}
- #endif
+#endif
// The common part of move/copy assigning
template <class Rhs> void assign_common(Rhs &&rhs) {
if (rhs.m_has_val) {
get() = std::forward<Rhs>(rhs).get();
} else {
- destroy_val();
+ destroy_val();
construct_error(std::forward<Rhs>(rhs).geterr());
}
} else {
}
#endif
- constexpr void destroy_val() {
- get().~T();
- }
+ TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
};
// This base class provides some handy member functions which can be used in
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))
unexpected<E>(std::forward<Args>(args)...);
this->m_has_val = false;
}
#endif
- constexpr void destroy_val() {
- //no-op
+ TL_EXPECTED_11_CONSTEXPR void destroy_val() {
+ // no-op
}
};
private detail::expected_delete_assign_base<T, E>,
private detail::expected_default_ctor_base<T, E> {
static_assert(!std::is_reference<T>::value, "T must not be a reference");
- static_assert(!std::is_same<T, std::remove_cv<in_place_t>>::value,
+ static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
"T must not be in_place_t");
- static_assert(!std::is_same<T, std::remove_cv<unexpect_t>>::value,
+ static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
"T must not be unexpect_t");
- static_assert(!std::is_same<T, std::remove_cv<unexpected<E>>>::value,
- "T must not be unexpected<E>");
+ static_assert(
+ !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
+ "T must not be unexpected<E>");
static_assert(!std::is_reference<E>::value, "E must not be a reference");
T *valptr() { return std::addressof(this->m_val); }
- const T *valptr() const { return std::addressof(this->m_val); }
+ const T *valptr() const { return std::addressof(this->m_val); }
unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
- const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); }
+ const unexpected<E> *errptr() const {
+ return std::addressof(this->m_unexpect);
+ }
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- U &val() {
+ TL_EXPECTED_11_CONSTEXPR U &val() {
return this->m_val;
}
- unexpected<E> &err() { return this->m_unexpect; }
+ TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- const U &val() const {
+ constexpr const U &val() const {
return this->m_val;
}
- const unexpected<E> &err() const { return this->m_unexpect; }
+ constexpr const unexpected<E> &err() const { return this->m_unexpect; }
using impl_base = detail::expected_move_assign_base<T, E>;
using ctor_base = detail::expected_default_ctor_base<T, E>;
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- /// \group and_then
- /// Carries out some operation which returns an expected on the stored object
- /// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
- /// returns an `expected<U>` for some `U`. \returns Let `U` be the result
- /// of `std::invoke(std::forward<F>(f), value())`. Returns an
- /// `expected<U>`. The return value is empty if `*this` is empty,
- /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
- /// is returned.
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
return and_then_impl(*this, std::forward<F>(f));
}
-
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
template <class F> constexpr auto and_then(F &&f) const & {
return and_then_impl(*this, std::forward<F>(f));
}
#ifndef TL_EXPECTED_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
template <class F> constexpr auto and_then(F &&f) const && {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
#endif
#else
- /// \group and_then
- /// Carries out some operation which returns an expected on the stored object
- /// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
- /// returns an `expected<U>` for some `U`. \returns Let `U` be the result
- /// of `std::invoke(std::forward<F>(f), value())`. Returns an
- /// `expected<U>`. The return value is empty if `*this` is empty,
- /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
- /// is returned.
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
template <class F>
TL_EXPECTED_11_CONSTEXPR auto
- and_then(F &&f) & -> decltype(and_then_impl(*this, std::forward<F>(f))) {
+ and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
+ std::forward<F>(f))) {
return and_then_impl(*this, std::forward<F>(f));
}
-
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
template <class F>
- TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(
- and_then_impl(std::move(*this), std::forward<F>(f))) {
+ TL_EXPECTED_11_CONSTEXPR auto
+ and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
+ std::forward<F>(f))) {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
template <class F>
- constexpr auto and_then(F &&f) const & -> decltype(
- and_then_impl(*this, std::forward<F>(f))) {
+ constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
+ std::declval<expected const &>(), std::forward<F>(f))) {
return and_then_impl(*this, std::forward<F>(f));
}
#ifndef TL_EXPECTED_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
template <class F>
- constexpr auto and_then(F &&f) const && -> decltype(
- and_then_impl(std::move(*this), std::forward<F>(f))) {
+ constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
+ std::declval<expected const &&>(), std::forward<F>(f))) {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
#endif
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise
- // returns an `expected<U,E>`. If `*this` is unexpected, the
- /// result is `*this`, otherwise an `expected<U,E>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
-
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const &;
template <class F> constexpr auto map(F &&f) const & {
return expected_map_impl(*this, std::forward<F>(f));
}
-
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const &&;
template <class F> constexpr auto map(F &&f) const && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
}
#else
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise
- // returns an `expected<U,E>`. If `*this` is unexpected, the
- /// result is `*this`, otherwise an `expected<U,E>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &;
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(
- expected_map_impl(std::declval<expected &>(), std::declval<F &&>()))
+ TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ std::declval<expected &>(), std::declval<F &&>()))
map(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
-
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &&;
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(
- expected_map_impl(std::declval<expected>(), std::declval<F &&>()))
+ TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ std::declval<F &&>()))
map(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const &;
template <class F>
constexpr decltype(expected_map_impl(std::declval<const expected &>(),
std::declval<F &&>()))
}
#ifndef TL_EXPECTED_NO_CONSTRR
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const &&;
template <class F>
constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- /// \brief Carries out some operation on the stored unexpected object if there
- /// is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. If `U` is `void`, returns an `expected<T,monostate>`, otherwise
- /// returns an `expected<T,U>`. If `*this` has an expected
- /// value, the result is `*this`, otherwise an `expected<T,U>` is constructed
- /// from `make_unexpected(std::invoke(std::forward<F>(f), value()))` and is
- /// returned.
- ///
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) &;
+ template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+ template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform(F &&f) const & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform(F &&f) const && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+#else
+ template <class F>
+ TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ std::declval<expected &>(), std::declval<F &&>()))
+ transform(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+ TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ std::declval<F &&>()))
+ transform(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F>
+ constexpr decltype(expected_map_impl(std::declval<const expected &>(),
+ std::declval<F &&>()))
+ transform(F &&f) const & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+
+#ifndef TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+ transform(F &&f) const && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+#endif
+#endif
+
+#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
-
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) const &;
template <class F> constexpr auto map_error(F &&f) const & {
return map_error_impl(*this, std::forward<F>(f));
}
-
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) const &&;
template <class F> constexpr auto map_error(F &&f) const && {
return map_error_impl(std::move(*this), std::forward<F>(f));
}
#else
- /// \brief Carries out some operation on the stored unexpected object if there
- /// is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns an `expected<T,U>`. If `*this` has an expected
- /// value, the result is `*this`, otherwise an `expected<T,U>` is constructed
- /// from `make_unexpected(std::invoke(std::forward<F>(f), value()))` and is
- /// returned.
- ///
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) &;
template <class F>
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
std::declval<F &&>()))
map_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
-
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) &&;
template <class F>
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
std::declval<F &&>()))
map_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
}
-
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) const &;
template <class F>
constexpr decltype(map_error_impl(std::declval<const expected &>(),
std::declval<F &&>()))
}
#ifndef TL_EXPECTED_NO_CONSTRR
- /// \group map_error
- /// \synopsis template <class F> constexpr auto map_error(F &&f) const &&;
template <class F>
constexpr decltype(map_error_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
}
#endif
#endif
+#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+ template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+ template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform_error(F &&f) const & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform_error(F &&f) const && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+#else
+ template <class F>
+ TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+ TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F>
+ constexpr decltype(map_error_impl(std::declval<const expected &>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) const & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
- /// \brief Calls `f` if the expectd is in the unexpected state
- /// \requires `F` is invokable with `E`, and `std::invoke_result_t<F>`
- /// must be void or convertible to `expcted<T,E>`.
- /// \effects If `*this` has a value, returns `*this`.
- /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)(E)` and returns
- /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`.
- ///
- /// \group or_else
+#ifndef TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(map_error_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) const && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+#endif
+#endif
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
return or_else_impl(*this, std::forward<F>(f));
}
template <class... Args,
detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
nullptr>
- constexpr expected(in_place_t, Args &&... args)
+ constexpr expected(in_place_t, Args &&...args)
: impl_base(in_place, std::forward<Args>(args)...),
ctor_base(detail::default_constructor_tag{}) {}
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected(in_place_t, std::initializer_list<U> il, Args &&... args)
+ constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
: impl_base(in_place, il, std::forward<Args>(args)...),
ctor_base(detail::default_constructor_tag{}) {}
- /// \group unexpected_ctor
- /// \synopsis EXPLICIT constexpr expected(const unexpected<G> &e);
template <class G = E,
detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
nullptr,
: impl_base(unexpect, e.value()),
ctor_base(detail::default_constructor_tag{}) {}
- /// \exclude
template <
class G = E,
detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
: impl_base(unexpect, e.value()),
ctor_base(detail::default_constructor_tag{}) {}
- /// \group unexpected_ctor
- /// \synopsis EXPLICIT constexpr expected(unexpected<G> &&e);
template <
class G = E,
detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
: impl_base(unexpect, std::move(e.value())),
ctor_base(detail::default_constructor_tag{}) {}
- /// \exclude
template <
class G = E,
detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
template <class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr>
- constexpr explicit expected(unexpect_t, Args &&... args)
+ constexpr explicit expected(unexpect_t, Args &&...args)
: impl_base(unexpect, std::forward<Args>(args)...),
ctor_base(detail::default_constructor_tag{}) {}
- /// \exclude
template <class U, class... Args,
detail::enable_if_t<std::is_constructible<
E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
- Args &&... args)
+ Args &&...args)
: impl_base(unexpect, il, std::forward<Args>(args)...),
ctor_base(detail::default_constructor_tag{}) {}
if (rhs.has_value()) {
this->construct(*rhs);
} else {
- this->construct_error(rhs.error());
+ this->construct_error(rhs.error());
}
}
- /// \exclude
template <class U, class G,
detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
std::is_convertible<G const &, E>::value)> * =
if (rhs.has_value()) {
this->construct(*rhs);
} else {
- this->construct_error(rhs.error());
- }
+ this->construct_error(rhs.error());
+ }
}
template <
if (rhs.has_value()) {
this->construct(std::move(*rhs));
} else {
- this->construct_error(std::move(rhs.error()));
- }
+ this->construct_error(std::move(rhs.error()));
+ }
}
- /// \exclude
template <
class U, class G,
detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
if (rhs.has_value()) {
this->construct(std::move(*rhs));
} else {
- this->construct_error(std::move(rhs.error()));
- }
+ this->construct_error(std::move(rhs.error()));
+ }
}
template <
explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
: expected(in_place, std::forward<U>(v)) {}
- /// \exclude
template <
class U = T,
detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
return *this;
}
- /// \exclude
template <
class U = T, class G = T,
detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
auto tmp = std::move(err());
err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
try {
- ::new (valptr()) T(std::move(v));
+ ::new (valptr()) T(std::forward<U>(v));
this->m_has_val = true;
} catch (...) {
err() = std::move(tmp);
throw;
}
- #else
- ::new (valptr()) T(std::move(v));
- this->m_has_val = true;
- #endif
+#else
+ ::new (valptr()) T(std::forward<U>(v));
+ this->m_has_val = true;
+#endif
}
return *this;
template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
T, Args &&...>::value> * = nullptr>
- void emplace(Args &&... args) {
+ void emplace(Args &&...args) {
if (has_value()) {
- val() = T(std::forward<Args>(args)...);
+ val().~T();
} else {
err().~unexpected<E>();
- ::new (valptr()) T(std::forward<Args>(args)...);
this->m_has_val = true;
}
+ ::new (valptr()) T(std::forward<Args>(args)...);
}
- /// \exclude
template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
T, Args &&...>::value> * = nullptr>
- void emplace(Args &&... args) {
+ void emplace(Args &&...args) {
if (has_value()) {
- val() = T(std::forward<Args>(args)...);
+ val().~T();
+ ::new (valptr()) T(std::forward<Args>(args)...);
} else {
auto tmp = std::move(err());
err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (valptr()) T(std::forward<Args>(args)...);
this->m_has_val = true;
err() = std::move(tmp);
throw;
}
- #else
+#else
::new (valptr()) T(std::forward<Args>(args)...);
this->m_has_val = true;
- #endif
+#endif
}
}
template <class U, class... Args,
detail::enable_if_t<std::is_nothrow_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- void emplace(std::initializer_list<U> il, Args &&... args) {
+ void emplace(std::initializer_list<U> il, Args &&...args) {
if (has_value()) {
T t(il, std::forward<Args>(args)...);
val() = std::move(t);
}
}
- /// \exclude
template <class U, class... Args,
detail::enable_if_t<!std::is_nothrow_constructible<
T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- void emplace(std::initializer_list<U> il, Args &&... args) {
+ void emplace(std::initializer_list<U> il, Args &&...args) {
if (has_value()) {
T t(il, std::forward<Args>(args)...);
val() = std::move(t);
auto tmp = std::move(err());
err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (valptr()) T(il, std::forward<Args>(args)...);
this->m_has_val = true;
err() = std::move(tmp);
throw;
}
- #else
+#else
::new (valptr()) T(il, std::forward<Args>(args)...);
this->m_has_val = true;
- #endif
+#endif
}
}
- // TODO SFINAE
- void swap(expected &rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value &&noexcept(
- swap(std::declval<T &>(), std::declval<T &>())) &&
- std::is_nothrow_move_constructible<E>::value &&
- noexcept(swap(std::declval<E &>(), std::declval<E &>()))) {
+private:
+ using t_is_void = std::true_type;
+ using t_is_not_void = std::false_type;
+ using t_is_nothrow_move_constructible = std::true_type;
+ using move_constructing_t_can_throw = std::false_type;
+ using e_is_nothrow_move_constructible = std::true_type;
+ using move_constructing_e_can_throw = std::false_type;
+
+ void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
+ // swapping void is a no-op
+ }
+
+ void swap_where_both_have_value(expected &rhs, t_is_not_void) {
+ using std::swap;
+ swap(val(), rhs.val());
+ }
+
+ void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
+ std::is_nothrow_move_constructible<E>::value) {
+ ::new (errptr()) unexpected_type(std::move(rhs.err()));
+ rhs.err().~unexpected_type();
+ std::swap(this->m_has_val, rhs.m_has_val);
+ }
+
+ void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
+ swap_where_only_one_has_value_and_t_is_not_void(
+ rhs, typename std::is_nothrow_move_constructible<T>::type{},
+ typename std::is_nothrow_move_constructible<E>::type{});
+ }
+
+ void swap_where_only_one_has_value_and_t_is_not_void(
+ expected &rhs, t_is_nothrow_move_constructible,
+ e_is_nothrow_move_constructible) noexcept {
+ auto temp = std::move(val());
+ val().~T();
+ ::new (errptr()) unexpected_type(std::move(rhs.err()));
+ rhs.err().~unexpected_type();
+ ::new (rhs.valptr()) T(std::move(temp));
+ std::swap(this->m_has_val, rhs.m_has_val);
+ }
+
+ void swap_where_only_one_has_value_and_t_is_not_void(
+ expected &rhs, t_is_nothrow_move_constructible,
+ move_constructing_e_can_throw) {
+ auto temp = std::move(val());
+ val().~T();
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (errptr()) unexpected_type(std::move(rhs.err()));
+ rhs.err().~unexpected_type();
+ ::new (rhs.valptr()) T(std::move(temp));
+ std::swap(this->m_has_val, rhs.m_has_val);
+ } catch (...) {
+ val() = std::move(temp);
+ throw;
+ }
+#else
+ ::new (errptr()) unexpected_type(std::move(rhs.err()));
+ rhs.err().~unexpected_type();
+ ::new (rhs.valptr()) T(std::move(temp));
+ std::swap(this->m_has_val, rhs.m_has_val);
+#endif
+ }
+
+ void swap_where_only_one_has_value_and_t_is_not_void(
+ expected &rhs, move_constructing_t_can_throw,
+ e_is_nothrow_move_constructible) {
+ auto temp = std::move(rhs.err());
+ rhs.err().~unexpected_type();
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (rhs.valptr()) T(std::move(val()));
+ val().~T();
+ ::new (errptr()) unexpected_type(std::move(temp));
+ std::swap(this->m_has_val, rhs.m_has_val);
+ } catch (...) {
+ rhs.err() = std::move(temp);
+ throw;
+ }
+#else
+ ::new (rhs.valptr()) T(std::move(val()));
+ val().~T();
+ ::new (errptr()) unexpected_type(std::move(temp));
+ std::swap(this->m_has_val, rhs.m_has_val);
+#endif
+ }
+
+public:
+ template <class OT = T, class OE = E>
+ detail::enable_if_t<detail::is_swappable<OT>::value &&
+ detail::is_swappable<OE>::value &&
+ (std::is_nothrow_move_constructible<OT>::value ||
+ std::is_nothrow_move_constructible<OE>::value)>
+ swap(expected &rhs) noexcept(
+ std::is_nothrow_move_constructible<T>::value
+ &&detail::is_nothrow_swappable<T>::value
+ &&std::is_nothrow_move_constructible<E>::value
+ &&detail::is_nothrow_swappable<E>::value) {
if (has_value() && rhs.has_value()) {
- using std::swap;
- swap(val(), rhs.val());
+ swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
} else if (!has_value() && rhs.has_value()) {
- using std::swap;
- swap(err(), rhs.err());
+ rhs.swap(*this);
} else if (has_value()) {
- auto temp = std::move(rhs.err());
- ::new (rhs.valptr()) T(val());
- ::new (errptr()) unexpected_type(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
+ swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
} else {
- auto temp = std::move(this->err());
- ::new (valptr()) T(rhs.val());
- ::new (errptr()) unexpected_type(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
+ using std::swap;
+ swap(err(), rhs.err());
}
}
- /// \returns a pointer to the stored value
- /// \requires a value is stored
- /// \group pointer
- constexpr const T *operator->() const { return valptr(); }
- /// \group pointer
- TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); }
+ constexpr const T *operator->() const {
+ TL_ASSERT(has_value());
+ return valptr();
+ }
+ TL_EXPECTED_11_CONSTEXPR T *operator->() {
+ TL_ASSERT(has_value());
+ return valptr();
+ }
- /// \returns the stored value
- /// \requires a value is stored
- /// \group deref
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &operator*() const & {
+ TL_ASSERT(has_value());
return val();
}
- /// \group deref
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &operator*() & {
+ TL_ASSERT(has_value());
return val();
}
- /// \group deref
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &&operator*() const && {
+ TL_ASSERT(has_value());
return std::move(val());
}
- /// \group deref
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
+ TL_ASSERT(has_value());
return std::move(val());
}
- /// \returns whether or not the optional has a value
- /// \group has_value
constexpr bool has_value() const noexcept { return this->m_has_val; }
- /// \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]
- ///
- /// \group value
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR const U &value() const & {
detail::throw_exception(bad_expected_access<E>(err().value()));
return val();
}
- /// \group value
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &value() & {
detail::throw_exception(bad_expected_access<E>(err().value()));
return val();
}
- /// \group value
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
if (!has_value())
- detail::throw_exception(bad_expected_access<E>(err().value()));
+ detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
return std::move(val());
}
- /// \group value
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &&value() && {
if (!has_value())
- detail::throw_exception(bad_expected_access<E>(err().value()));
+ detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
return std::move(val());
}
- /// \returns the unexpected value
- /// \requires there is an unexpected value
- /// \group error
- constexpr const E &error() const & { return err().value(); }
- /// \group error
- TL_EXPECTED_11_CONSTEXPR E &error() & { return err().value(); }
- /// \group error
- constexpr const E &&error() const && { return std::move(err().value()); }
- /// \group error
- TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(err().value()); }
+ constexpr const E &error() const & {
+ TL_ASSERT(!has_value());
+ return err().value();
+ }
+ TL_EXPECTED_11_CONSTEXPR E &error() & {
+ TL_ASSERT(!has_value());
+ return err().value();
+ }
+ constexpr const E &&error() const && {
+ TL_ASSERT(!has_value());
+ return std::move(err().value());
+ }
+ TL_EXPECTED_11_CONSTEXPR E &&error() && {
+ TL_ASSERT(!has_value());
+ return std::move(err().value());
+ }
- /// \returns the stored value if there is one, otherwise returns `u`
- /// \group value_or
template <class U> constexpr T value_or(U &&v) const & {
static_assert(std::is_copy_constructible<T>::value &&
std::is_convertible<U &&, T>::value,
"T must be copy-constructible and convertible to from U&&");
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
}
- /// \group value_or
template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
static_assert(std::is_move_constructible<T>::value &&
std::is_convertible<U &&, T>::value,
}
};
-/// \exclude
namespace detail {
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;
return exp.has_value()
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
- : Ret(unexpect, exp.error());
+ : Ret(unexpect, std::forward<Exp>(exp).error());
}
template <class Exp, class 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());
+ : Ret(unexpect, std::forward<Exp>(exp).error());
}
#else
template <class> struct TC;
return exp.has_value()
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
- : Ret(unexpect, exp.error());
+ : Ret(unexpect, std::forward<Exp>(exp).error());
}
template <class Exp, class 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());
+ : Ret(unexpect, std::forward<Exp>(exp).error());
}
#endif
#ifdef TL_EXPECTED_CXX14
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
*std::declval<Exp>())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
*std::declval<Exp>())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
auto expected_map_impl(Exp &&exp, F &&f) {
}
return result(unexpect, std::forward<Exp>(exp).error());
-}
+}
#else
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
*std::declval<Exp>())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
*std::declval<Exp>())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
}
return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
-}
+}
#endif
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
std::forward<Exp>(exp).error()));
}
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
return result(unexpect, monostate{});
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
std::forward<Exp>(exp).error()));
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
return result(unexpect, monostate{});
-}
+}
#else
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
}
template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
+ detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
return result(unexpect, monostate{});
-}
+}
#endif
#ifdef TL_EXPECTED_CXX14
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
constexpr auto or_else_impl(Exp &&exp, F &&f) {
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value()
- ? std::forward<Exp>(exp)
- : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
+ return exp.has_value() ? std::forward<Exp>(exp)
+ : detail::invoke(std::forward<F>(f),
+ std::forward<Exp>(exp).error());
}
template <class Exp, class F,
std::declval<Exp>().error())),
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
- return exp.has_value()
- ? std::forward<Exp>(exp)
- : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
- std::forward<Exp>(exp));
+ return exp.has_value() ? std::forward<Exp>(exp)
+ : (detail::invoke(std::forward<F>(f),
+ std::forward<Exp>(exp).error()),
+ std::forward<Exp>(exp));
}
#else
template <class Exp, class F,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
+ detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
auto or_else_impl(Exp &&exp, F &&f) -> Ret {
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value()
- ? std::forward<Exp>(exp)
- : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
+ return exp.has_value() ? std::forward<Exp>(exp)
+ : detail::invoke(std::forward<F>(f),
+ std::forward<Exp>(exp).error());
}
template <class Exp, class F,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
+ detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
- return exp.has_value()
- ? std::forward<Exp>(exp)
- : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
- std::forward<Exp>(exp));
+ return exp.has_value() ? std::forward<Exp>(exp)
+ : (detail::invoke(std::forward<F>(f),
+ std::forward<Exp>(exp).error()),
+ std::forward<Exp>(exp));
}
#endif
} // namespace detail
? true
: (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
}
+template <class E, class F>
+constexpr bool operator==(const expected<void, E> &lhs,
+ const expected<void, F> &rhs) {
+ return (lhs.has_value() != rhs.has_value())
+ ? false
+ : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
+}
+template <class E, class F>
+constexpr bool operator!=(const expected<void, E> &lhs,
+ const expected<void, F> &rhs) {
+ return (lhs.has_value() != rhs.has_value())
+ ? true
+ : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
+}
template <class T, class E, class U>
constexpr bool operator==(const expected<T, E> &x, const U &v) {
return x.has_value() ? true : x.error() != e.value();
}
-// TODO is_swappable
template <class T, class E,
- detail::enable_if_t<std::is_move_constructible<T>::value &&
- std::is_move_constructible<E>::value> * = nullptr>
+ detail::enable_if_t<(std::is_void<T>::value ||
+ std::is_move_constructible<T>::value) &&
+ detail::is_swappable<T>::value &&
+ std::is_move_constructible<E>::value &&
+ detail::is_swappable<E>::value> * = nullptr>
void swap(expected<T, E> &lhs,
expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
lhs.swap(rhs);
}
} // namespace tl
-#define TL_OPTIONAL_EXPECTED_MUTEX
#endif