]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
common: bump up tl:expected to latest version 50490/head
authorRonen Friedman <rfriedma@redhat.com>
Mon, 13 Mar 2023 08:03:09 +0000 (03:03 -0500)
committerRonen Friedman <rfriedma@redhat.com>
Mon, 13 Mar 2023 08:03:09 +0000 (03:03 -0500)
The newer version contains bug fixes and improvements.
This implementation matches C++23 std::expected(including the monadic
interface P2505R5), with a known caveat: using the 'map' instead of
'transform'.

Signed-off-by: Ronen Friedman <rfriedma@redhat.com>
src/include/expected.hpp

index 740c6ad249506f84eec6f0c383f65768c63bf461..7fd646774b6801fda42f4bc6562130b55a1c4c30 100644 (file)
@@ -1,6 +1,8 @@
 ///
 // 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
@@ -14,8 +16,9 @@
 #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>
@@ -27,7 +30,6 @@
 #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
 
@@ -120,10 +121,8 @@ namespace tl {
 
 #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
 
@@ -132,18 +131,14 @@ template <class T, class E> class expected;
 
 #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");
@@ -153,82 +148,77 @@ public:
 
   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
 }
 
@@ -251,20 +241,58 @@ template <class B, class... Bs>
 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)...);
@@ -275,9 +303,11 @@ template <class F, class, class... Us> struct invoke_result_impl;
 
 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>
@@ -285,6 +315,77 @@ using invoke_result = invoke_result_impl<F, void, 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
@@ -325,18 +426,13 @@ using is_move_constructible_or_void =
     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{};
@@ -356,19 +452,19 @@ struct expected_storage_base {
   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,
@@ -376,7 +472,7 @@ struct expected_storage_base {
                 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() {
@@ -387,9 +483,9 @@ struct expected_storage_base {
     }
   }
   union {
-    char m_no_init;
     T m_val;
     unexpected<E> m_unexpect;
+    char m_no_init;
   };
   bool m_has_val;
 };
@@ -403,19 +499,19 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
   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,
@@ -423,14 +519,14 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
                 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;
 };
@@ -444,19 +540,19 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
   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,
@@ -464,7 +560,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
                 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() {
@@ -474,9 +570,9 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
   }
 
   union {
-    char m_no_init;
     T m_val;
     unexpected<E> m_unexpect;
+    char m_no_init;
   };
   bool m_has_val;
 };
@@ -489,19 +585,19 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
   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,
@@ -509,7 +605,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
                 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() {
@@ -518,16 +614,22 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
     }
   }
   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) {}
@@ -535,7 +637,7 @@ template <class E> struct expected_storage_base<void, E, false, 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,
@@ -543,14 +645,14 @@ template <class E> struct expected_storage_base<void, E, false, true> {
                 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;
 };
@@ -565,7 +667,7 @@ template <class E> struct expected_storage_base<void, E, false, false> {
   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,
@@ -573,7 +675,7 @@ template <class E> struct expected_storage_base<void, E, false, false> {
                 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() {
@@ -583,8 +685,8 @@ template <class E> struct expected_storage_base<void, E, false, false> {
   }
 
   union {
-    char m_dummy;
     unexpected<E> m_unexpect;
+    char m_dummy;
   };
   bool m_has_val;
 };
@@ -595,7 +697,7 @@ template <class T, class E>
 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;
   }
@@ -605,13 +707,13 @@ struct expected_operations_base : expected_storage_base<T, E> {
     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.
@@ -661,12 +763,16 @@ struct expected_operations_base : expected_storage_base<T, E> {
       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);
     }
@@ -692,18 +798,22 @@ struct expected_operations_base : expected_storage_base<T, E> {
     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 {
@@ -720,11 +830,11 @@ struct expected_operations_base : expected_storage_base<T, E> {
       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) {
@@ -732,7 +842,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
       if (rhs.m_has_val) {
         get() = std::forward<Rhs>(rhs).get();
       } else {
-               destroy_val();
+        destroy_val();
         construct_error(std::forward<Rhs>(rhs).geterr());
       }
     } else {
@@ -764,9 +874,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
   }
 #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
@@ -783,7 +891,7 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
     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;
@@ -819,8 +927,8 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
   }
 #endif
 
-  constexpr void destroy_val() {
-         //no-op
+  TL_EXPECTED_11_CONSTEXPR void destroy_val() {
+    // no-op
   }
 };
 
@@ -1141,32 +1249,35 @@ class expected : private detail::expected_move_assign_base<T, E>,
                  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>;
@@ -1178,77 +1289,45 @@ public:
 
 #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
@@ -1256,66 +1335,31 @@ public:
 
 #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 &&>()))
@@ -1324,8 +1368,6 @@ public:
   }
 
 #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 &&>()))
@@ -1337,67 +1379,75 @@ public:
 
 #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 &&>()))
@@ -1406,8 +1456,6 @@ public:
   }
 
 #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 &&>()))
@@ -1416,15 +1464,49 @@ public:
   }
 #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));
   }
@@ -1451,19 +1533,17 @@ public:
   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,
@@ -1473,7 +1553,6 @@ public:
       : 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> * =
@@ -1483,8 +1562,6 @@ public:
       : 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,
@@ -1494,7 +1571,6 @@ public:
       : 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,
@@ -1507,16 +1583,15 @@ public:
   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{}) {}
 
@@ -1531,11 +1606,10 @@ public:
     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)> * =
@@ -1547,8 +1621,8 @@ public:
     if (rhs.has_value()) {
       this->construct(*rhs);
     } else {
-      this->construct_error(rhs.error());        
-    }      
+      this->construct_error(rhs.error());
+    }
   }
 
   template <
@@ -1561,11 +1635,10 @@ public:
     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 &&
@@ -1576,8 +1649,8 @@ public:
     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 <
@@ -1587,7 +1660,6 @@ public:
   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,
@@ -1619,7 +1691,6 @@ public:
     return *this;
   }
 
-  /// \exclude
   template <
       class U = T, class G = T,
       detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
@@ -1639,18 +1710,18 @@ public:
       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;
@@ -1688,27 +1759,27 @@ public:
 
   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;
@@ -1716,17 +1787,17 @@ public:
         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);
@@ -1737,11 +1808,10 @@ public:
     }
   }
 
-  /// \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);
@@ -1749,7 +1819,7 @@ public:
       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;
@@ -1757,82 +1827,160 @@ public:
         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 & {
@@ -1840,7 +1988,6 @@ public:
       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() & {
@@ -1848,43 +1995,44 @@ public:
       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,
@@ -1893,7 +2041,6 @@ public:
   }
 };
 
-/// \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;
@@ -1909,7 +2056,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
 
   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,
@@ -1919,7 +2066,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
 
   return exp.has_value() ? detail::invoke(std::forward<F>(f))
-                         : Ret(unexpect, exp.error());
+                         : Ret(unexpect, std::forward<Exp>(exp).error());
 }
 #else
 template <class> struct TC;
@@ -1932,7 +2079,7 @@ auto and_then_impl(Exp &&exp, F &&f) -> Ret {
 
   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,
@@ -1942,13 +2089,13 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
 
   return exp.has_value() ? detail::invoke(std::forward<F>(f))
-                         : Ret(unexpect, exp.error());
+                         : 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>
@@ -1960,7 +2107,7 @@ constexpr auto expected_map_impl(Exp &&exp, F &&f) {
 }
 
 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>
@@ -1985,7 +2132,7 @@ constexpr auto expected_map_impl(Exp &&exp, F &&f) {
 }
 
 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) {
@@ -1996,10 +2143,10 @@ 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>
@@ -2014,7 +2161,7 @@ constexpr auto expected_map_impl(Exp &&exp, F &&f)
 }
 
 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>
@@ -2029,7 +2176,7 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
 }
 
 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>
 
@@ -2042,7 +2189,7 @@ constexpr auto expected_map_impl(Exp &&exp, F &&f)
 }
 
 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>
 
@@ -2053,13 +2200,13 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
   }
 
   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>
@@ -2071,7 +2218,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
                                                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>
@@ -2085,7 +2232,7 @@ auto map_error_impl(Exp &&exp, F &&f) {
   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>
@@ -2097,7 +2244,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
                                                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>
@@ -2109,10 +2256,10 @@ auto map_error_impl(Exp &&exp, F &&f) {
 
   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>
@@ -2127,7 +2274,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f)
 }
 
 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>
@@ -2142,7 +2289,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, 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>
@@ -2157,7 +2304,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f)
 }
 
 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>
@@ -2169,7 +2316,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
 
   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
   return result(unexpect, monostate{});
-}    
+}
 #endif
 
 #ifdef TL_EXPECTED_CXX14
@@ -2179,9 +2326,9 @@ template <class Exp, class F,
           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,
@@ -2189,32 +2336,32 @@ 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
@@ -2233,6 +2380,20 @@ constexpr bool operator!=(const expected<T, E> &lhs,
              ? 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) {
@@ -2268,15 +2429,16 @@ constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
   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