summaryrefslogtreecommitdiff
path: root/lib/result
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2022-10-11 22:37:04 +1100
committerjacqueline <me@jacqueline.id.au>2022-10-11 22:37:04 +1100
commit7d7dc4f9963995d63b1b8f484f40b3ae480011ea (patch)
tree30ae7f45f9553ae9b18502d4932a1d51fc304cd7 /lib/result
parentb9ee0eb88fd1c02aeb4cb1d1047e21119f8e2bf4 (diff)
downloadtangara-fw-7d7dc4f9963995d63b1b8f484f40b3ae480011ea.tar.gz
add a cool result library
Diffstat (limited to 'lib/result')
-rw-r--r--lib/result/CMakeLists.txt1
-rw-r--r--lib/result/LICENSE.txt21
-rw-r--r--lib/result/include/result.hpp5944
3 files changed, 5966 insertions, 0 deletions
diff --git a/lib/result/CMakeLists.txt b/lib/result/CMakeLists.txt
new file mode 100644
index 00000000..67111692
--- /dev/null
+++ b/lib/result/CMakeLists.txt
@@ -0,0 +1 @@
+idf_component_register(INCLUDE_DIRS "include")
diff --git a/lib/result/LICENSE.txt b/lib/result/LICENSE.txt
new file mode 100644
index 00000000..1dcfde87
--- /dev/null
+++ b/lib/result/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-2021 Matthew Rodusek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/lib/result/include/result.hpp b/lib/result/include/result.hpp
new file mode 100644
index 00000000..96243f72
--- /dev/null
+++ b/lib/result/include/result.hpp
@@ -0,0 +1,5944 @@
+////////////////////////////////////////////////////////////////////////////////
+/// \file result.hpp
+///
+/// \brief This header contains the 'result' monadic type for indicating
+/// possible error conditions
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+ The MIT License (MIT)
+
+ Copyright (c) 2017-2021 Matthew Rodusek All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#ifndef RESULT_RESULT_HPP
+#define RESULT_RESULT_HPP
+
+#include <cstddef> // std::size_t
+#include <type_traits> // std::enable_if, std::is_constructible, etc
+#include <new> // placement-new
+#include <memory> // std::address_of
+#include <functional> // std::reference_wrapper, std::invoke
+#include <utility> // std::in_place_t, std::forward
+#include <initializer_list> // std::initializer_list
+#include <string> // std::string (for exception message)
+
+#if defined(RESULT_EXCEPTIONS_DISABLED)
+# include <cstdio> // std::fprintf, stderr
+#else
+# include <stdexcept> // std::logic_error
+#endif
+
+#if __cplusplus >= 201402L
+# define RESULT_CPP14_CONSTEXPR constexpr
+#else
+# define RESULT_CPP14_CONSTEXPR
+#endif
+
+#if __cplusplus >= 201703L
+# define RESULT_CPP17_INLINE inline
+#else
+# define RESULT_CPP17_INLINE
+#endif
+
+#if defined(__clang__) && defined(_MSC_VER)
+# define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden")))
+#elif defined(__clang__) || defined(__GNUC__)
+# define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden"), always_inline))
+#elif defined(_MSC_VER)
+# define RESULT_INLINE_VISIBILITY __forceinline
+#else
+# define RESULT_INLINE_VISIBILITY
+#endif
+
+// [[clang::warn_unused_result]] is more full-featured than gcc's variant, since
+// it supports being applied to class objects.
+#if __cplusplus >= 201703L
+# define RESULT_NODISCARD [[nodiscard]]
+# define RESULT_WARN_UNUSED [[nodiscard]]
+#elif defined(__clang__) && ((__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 9)))
+# define RESULT_NODISCARD [[clang::warn_unused_result]]
+# define RESULT_WARN_UNUSED [[clang::warn_unused_result]]
+#elif defined(__GNUC__)
+# define RESULT_NODISCARD
+# define RESULT_WARN_UNUSED [[gnu::warn_unused_result]]
+#else
+# define RESULT_WARN_UNUSED
+# define RESULT_NODISCARD
+#endif
+
+#if defined(RESULT_NAMESPACE)
+# define RESULT_NAMESPACE_INTERNAL RESULT_NAMESPACE
+#else
+# define RESULT_NAMESPACE_INTERNAL cpp
+#endif
+#define RESULT_NS_IMPL RESULT_NAMESPACE_INTERNAL::bitwizeshift
+
+// clang's `-Wdocumentation-unknown-command` flag is bugged and does not
+// understand `\copydoc` tags, despite this being a valid doxygen tag.
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+
+namespace RESULT_NAMESPACE_INTERNAL {
+inline namespace bitwizeshift {
+
+ //===========================================================================
+ // utilities : constexpr forward
+ //===========================================================================
+
+ // std::forward is not constexpr until C++14
+ namespace detail {
+#if __cplusplus >= 201402L
+ using std::forward;
+#else
+ template <typename T>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto forward(typename std::remove_reference<T>::type& t)
+ noexcept -> T&&
+ {
+ return static_cast<T&&>(t);
+ }
+
+ template <typename T>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto forward(typename std::remove_reference<T>::type&& t)
+ noexcept -> T&&
+ {
+ return static_cast<T&&>(t);
+ }
+#endif
+ } // namespace detail
+
+
+ //===========================================================================
+ // utilities : invoke / invoke_result
+ //===========================================================================
+
+ // std::invoke was introduced in C++17
+
+ namespace detail {
+#if __cplusplus >= 201703L
+ using std::invoke;
+ using std::invoke_result;
+ using std::invoke_result_t;
+#else
+ template<typename T>
+ struct is_reference_wrapper : std::false_type{};
+
+ template<typename U>
+ struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type{};
+
+ //-------------------------------------------------------------------------
+
+ template <typename Base, typename T, typename Derived, typename... Args,
+ typename = typename std::enable_if<
+ std::is_function<T>::value &&
+ std::is_base_of<Base, typename std::decay<Derived>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmf, Derived&& ref, Args&&... args)
+ noexcept(noexcept((::RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmf)(::RESULT_NS_IMPL::detail::forward<Args>(args)...)))
+ -> decltype((::RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmf)(::RESULT_NS_IMPL::detail::forward<Args>(args)...))
+ {
+ return (RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...);
+ }
+
+ template <typename Base, typename T, typename RefWrap, typename... Args,
+ typename = typename std::enable_if<
+ std::is_function<T>::value &&
+ is_reference_wrapper<typename std::decay<RefWrap>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmf, RefWrap&& ref, Args&&... args)
+ noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...)))
+ -> decltype((ref.get().*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...))
+ {
+ return (ref.get().*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...);
+ }
+
+ template <typename Base, typename T, typename Pointer, typename... Args,
+ typename = typename std::enable_if<
+ std::is_function<T>::value &&
+ !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
+ !std::is_base_of<Base, typename std::decay<Pointer>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmf, Pointer&& ptr, Args&&... args)
+ noexcept(noexcept(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...)))
+ -> decltype(((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...))
+ {
+ return ((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...);
+ }
+
+ template <typename Base, typename T, typename Derived,
+ typename = typename std::enable_if<
+ !std::is_function<T>::value &&
+ std::is_base_of<Base, typename std::decay<Derived>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmd, Derived&& ref)
+ noexcept(noexcept(std::forward<Derived>(ref).*pmd))
+ -> decltype(RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmd)
+ {
+ return RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmd;
+ }
+
+ template <typename Base, typename T, typename RefWrap,
+ typename = typename std::enable_if<
+ !std::is_function<T>::value &&
+ is_reference_wrapper<typename std::decay<RefWrap>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmd, RefWrap&& ref)
+ noexcept(noexcept(ref.get().*pmd))
+ -> decltype(ref.get().*pmd)
+ {
+ return ref.get().*pmd;
+ }
+
+ template <typename Base, typename T, typename Pointer,
+ typename = typename std::enable_if<
+ !std::is_function<T>::value &&
+ !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
+ !std::is_base_of<Base, typename std::decay<Pointer>::type>::value
+ >::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(T Base::*pmd, Pointer&& ptr)
+ noexcept(noexcept((*std::forward<Pointer>(ptr)).*pmd))
+ -> decltype((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmd)
+ {
+ return (*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmd;
+ }
+
+ template <typename F, typename... Args,
+ typename = typename std::enable_if<!std::is_member_pointer<typename std::decay<F>::type>::value>::type>
+ inline RESULT_INLINE_VISIBILITY constexpr
+ auto invoke(F&& f, Args&&... args)
+ noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...)))
+ -> decltype(RESULT_NS_IMPL::detail::forward<F>(f)(RESULT_NS_IMPL::detail::forward<Args>(args)...))
+ {
+ return RESULT_NS_IMPL::detail::forward<F>(f)(RESULT_NS_IMPL::detail::forward<Args>(args)...);
+ }
+
+ template<typename Fn, typename...Args>
+ struct is_invocable
+ {
+ template <typename Fn2, typename...Args2>
+ static auto test( Fn2&&, Args2&&... )
+ -> decltype(invoke(std::declval<Fn2>(), std::declval<Args2>()...), std::true_type{});
+
+ static auto test(...)
+ -> std::false_type;
+
+ using type = decltype(test(std::declval<Fn>(), std::declval<Args>()...));
+ static constexpr bool value = type::value;
+ };
+
+ template <bool B, typename Fn, typename...Args>
+ struct invoke_result_impl {
+ using type = decltype(RESULT_NS_IMPL::detail::invoke(std::declval<Fn>(), std::declval<Args>()...));
+ };
+ template <typename Fn, typename...Args>
+ struct invoke_result_impl<false, Fn, Args...>{};
+
+ template <typename Fn, typename...Args>
+ struct invoke_result
+ : invoke_result_impl<is_invocable<Fn,Args...>::value, Fn, Args...>{};
+
+ template <typename Fn, typename...Args>
+ using invoke_result_t = typename invoke_result<Fn, Args...>::type;
+#endif
+ }
+
+ //===========================================================================
+ // struct : in_place_t
+ //===========================================================================
+
+#if __cplusplus >= 201703L
+ using std::in_place_t;
+ using std::in_place;
+#else
+ /// \brief A structure for representing in-place construction
+ struct in_place_t
+ {
+ explicit in_place_t() = default;
+ };
+ RESULT_CPP17_INLINE constexpr auto in_place = in_place_t{};
+#endif
+
+ //===========================================================================
+ // struct : in_place_t
+ //===========================================================================
+
+ /// \brief A structure for representing in-place construction of an error type
+ struct in_place_error_t
+ {
+ explicit in_place_error_t() = default;
+ };
+
+ RESULT_CPP17_INLINE constexpr auto in_place_error = in_place_error_t{};
+
+ //===========================================================================
+ // forward-declarations
+ //===========================================================================
+
+ template <typename>
+ class failure;
+
+ template <typename, typename>
+ class result;
+
+ template <typename>
+ class bad_result_access;
+
+ //===========================================================================
+ // traits
+ //===========================================================================
+
+ template <typename T>
+ struct is_failure : std::false_type{};
+ template <typename E>
+ struct is_failure<failure<E>> : std::true_type{};
+
+ template <typename T>
+ struct is_result : std::false_type{};
+ template <typename T, typename E>
+ struct is_result<result<T,E>> : std::true_type{};
+
+ //===========================================================================
+ // trait : detail::wrapped_result_type
+ //===========================================================================
+
+ namespace detail {
+
+ template <typename T>
+ using wrapped_result_type = typename std::conditional<
+ std::is_lvalue_reference<T>::value,
+ std::reference_wrapper<
+ typename std::remove_reference<T>::type
+ >,
+ typename std::remove_const<T>::type
+ >::type;
+
+ } // namespace detail
+
+#if !defined(RESULT_DISABLE_EXCEPTIONS)
+
+ //===========================================================================
+ // class : bad_result_access<E>
+ //===========================================================================
+
+ /////////////////////////////////////////////////////////////////////////////
+ /// \brief An exception thrown when result::value is accessed without
+ /// a contained value
+ /////////////////////////////////////////////////////////////////////////////
+ template <typename E>
+ class bad_result_access : public std::logic_error
+ {
+ //-------------------------------------------------------------------------
+ // Constructor / Assignment
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \brief Constructs this exception using the underlying error type for
+ /// the error type
+ ///
+ /// \param error the underlying error
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
+ explicit bad_result_access(E2&& error);
+
+ /// \{
+ /// \brief Constructs this exception using the underlying error type for
+ /// the error and a message
+ ///
+ /// \param what_arg the message for the failure
+ /// \param error the underlying error
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
+ bad_result_access(const char* what_arg, E2&& error);
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
+ bad_result_access(const std::string& what_arg, E2&& error);
+ /// \}
+
+ bad_result_access(const bad_result_access& other) = default;
+ bad_result_access(bad_result_access&& other) = default;
+
+ //-------------------------------------------------------------------------
+
+ auto operator=(const bad_result_access& other) -> bad_result_access& = default;
+ auto operator=(bad_result_access&& other) -> bad_result_access& = default;
+
+ /// \{
+ /// \brief Gets the underlying error
+ ///
+ /// \return the error
+ auto error() & noexcept -> E&;
+ auto error() && noexcept -> E&&;
+ auto error() const & noexcept -> const E&;
+ auto error() const && noexcept -> const E&&;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Private Members
+ //-------------------------------------------------------------------------
+ private:
+
+ E m_error;
+ };
+
+#endif
+
+ namespace detail {
+
+ template <typename E, typename E2>
+ using failure_is_value_convertible = std::integral_constant<bool,(
+ std::is_constructible<E, E2&&>::value &&
+ !std::is_same<typename std::decay<E2>::type, in_place_t>::value &&
+ !is_failure<typename std::decay<E2>::type>::value &&
+ !is_result<typename std::decay<E2>::type>::value
+ )>;
+
+ template <typename E, typename E2>
+ using failure_is_explicit_value_convertible = std::integral_constant<bool,(
+ failure_is_value_convertible<E, E2>::value &&
+ !std::is_convertible<E2, E>::value
+ )>;
+
+ template <typename E, typename E2>
+ using failure_is_implicit_value_convertible = std::integral_constant<bool,(
+ failure_is_value_convertible<E, E2>::value &&
+ std::is_convertible<E2, E>::value
+ )>;
+
+ template <typename E, typename E2>
+ using failure_is_value_assignable = std::integral_constant<bool,(
+ !is_result<typename std::decay<E2>::type>::value &&
+ !is_failure<typename std::decay<E2>::type>::value &&
+ std::is_assignable<wrapped_result_type<E>&,E2>::value
+ )>;
+
+ } // namespace detail
+
+ //===========================================================================
+ // class : failure_type
+ //===========================================================================
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// \brief A semantic type used for distinguishing failure values in an
+ /// API that returns result types
+ ///
+ /// \tparam E the error type
+ //////////////////////////////////////////////////////////////////////////////
+ template <typename E>
+ class failure
+ {
+ static_assert(
+ !is_result<typename std::decay<E>::type>::value,
+ "A (possibly CV-qualified) result 'E' type is ill-formed."
+ );
+ static_assert(
+ !is_failure<typename std::decay<E>::type>::value,
+ "A (possibly CV-qualified) failure 'E' type is ill-formed."
+ );
+ static_assert(
+ !std::is_void<typename std::decay<E>::type>::value,
+ "A (possibly CV-qualified) 'void' 'E' type is ill-formed."
+ );
+ static_assert(
+ !std::is_rvalue_reference<E>::value,
+ "rvalue references for 'E' type is ill-formed. "
+ "Only lvalue references are valid."
+ );
+
+ //-------------------------------------------------------------------------
+ // Public Member Types
+ //-------------------------------------------------------------------------
+ public:
+
+ using error_type = E;
+
+ //-------------------------------------------------------------------------
+ // Constructors / Assignment
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \brief Constructs a failure via default construction
+ failure() = default;
+
+ /// \brief Constructs a failure by delegating construction to the
+ /// underlying constructor
+ ///
+ /// \param args the arguments to forward to E's constructor
+ template <typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,Args...>::value>::type>
+ constexpr failure(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ /// \brief Constructs a failure by delegating construction to the
+ /// underlying constructor
+ ///
+ /// \param ilist the initializer list
+ /// \param args the arguments to forward to E's constructor
+ template <typename U, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,std::initializer_list<U>,Args...>::value>::type>
+ constexpr failure(in_place_t, std::initializer_list<U> ilist, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value);
+
+ /// \{
+ /// \brief Constructs a failure from the given error
+ ///
+ /// \param error the error to create a failure from
+ template <typename E2,
+ typename std::enable_if<detail::failure_is_implicit_value_convertible<E,E2>::value,int>::type = 0>
+ constexpr failure(E2&& error)
+ noexcept(std::is_nothrow_constructible<E,E2>::value);
+ template <typename E2,
+ typename std::enable_if<detail::failure_is_explicit_value_convertible<E,E2>::value,int>::type = 0>
+ constexpr explicit failure(E2&& error)
+ noexcept(std::is_nothrow_constructible<E,E2>::value);
+ /// \}
+
+ /// \brief Constructs this failure by copying the contents of an existing
+ /// one
+ ///
+ /// \param other the other failure to copy
+ /* implicit */ failure(const failure& other) = default;
+
+ /// \brief Constructs this failure by moving the contents of an existing
+ /// one
+ ///
+ /// \param other the other failure to move
+ /* implicit */ failure(failure&& other) = default;
+
+ /// \brief Constructs this failure by copy-converting \p other
+ ///
+ /// \param other the other failure to copy
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,const E2&>::value>::type>
+ constexpr /* implicit */ failure(const failure<E2>& other)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value);
+
+ /// \brief Constructs this failure by move-converting \p other
+ ///
+ /// \param other the other failure to copy
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2&&>::value>::type>
+ constexpr /* implicit */ failure(failure<E2>&& other)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value);
+
+ //--------------------------------------------------------------------------
+
+ /// \brief Assigns the value of \p error to this failure through
+ /// move-assignment
+ ///
+ /// \param error the value to assign
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<detail::failure_is_value_assignable<E,E2>::value>::type>
+ RESULT_CPP14_CONSTEXPR
+ auto operator=(E2&& error)
+ noexcept(std::is_nothrow_assignable<E,E2>::value || std::is_lvalue_reference<E>::value) -> failure&;
+
+ /// \brief Assigns the contents of \p other to this by copy-assignment
+ ///
+ /// \param other the other failure to copy
+ /// \return reference to `(*this)`
+ auto operator=(const failure& other) -> failure& = default;
+
+ /// \brief Assigns the contents of \p other to this by move-assignment
+ ///
+ /// \param other the other failure to move
+ /// \return reference to `(*this)`
+ auto operator=(failure&& other) -> failure& = default;
+
+ /// \brief Assigns the contents of \p other to this by copy conversion
+ ///
+ /// \param other the other failure to copy-convert
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<std::is_assignable<E&,const E2&>::value>::type>
+ RESULT_CPP14_CONSTEXPR
+ auto operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E,const E2&>::value) -> failure&;
+
+ /// \brief Assigns the contents of \p other to this by move conversion
+ ///
+ /// \param other the other failure to move-convert
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<std::is_assignable<E&,E2&&>::value>::type>
+ RESULT_CPP14_CONSTEXPR
+ auto operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E,E2&&>::value) -> failure&;
+
+ //--------------------------------------------------------------------------
+ // Observers
+ //--------------------------------------------------------------------------
+ public:
+
+ /// \{
+ /// \brief Gets the underlying error
+ ///
+ /// \return the underlying error
+ RESULT_CPP14_CONSTEXPR
+ auto error() & noexcept
+ -> typename std::add_lvalue_reference<E>::type;
+ RESULT_CPP14_CONSTEXPR
+ auto error() && noexcept
+ -> typename std::add_rvalue_reference<E>::type;
+ constexpr auto error() const & noexcept
+ -> typename std::add_lvalue_reference<typename std::add_const<E>::type>::type;
+ constexpr auto error() const && noexcept
+ -> typename std::add_rvalue_reference<typename std::add_const<E>::type>::type;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Private Member Types
+ //-------------------------------------------------------------------------
+ private:
+
+ using underlying_type = detail::wrapped_result_type<E>;
+
+ //-------------------------------------------------------------------------
+ // Private Members
+ //-------------------------------------------------------------------------
+ private:
+
+ underlying_type m_failure;
+ };
+
+#if __cplusplus >= 201703L
+ template <typename T>
+ failure(std::reference_wrapper<T>) -> failure<T&>;
+
+ template <typename T>
+ failure(T&&) -> failure<typename std::decay<T>::type>;
+#endif
+
+ //===========================================================================
+ // non-member functions : class : failure
+ //===========================================================================
+
+ //---------------------------------------------------------------------------
+ // Comparison
+ //---------------------------------------------------------------------------
+
+ template <typename E1, typename E2>
+ constexpr auto operator==(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator!=(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator<(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator>(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator<=(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator>=(const failure<E1>& lhs,
+ const failure<E2>& rhs) noexcept -> bool;
+
+ //---------------------------------------------------------------------------
+ // Utilities
+ //---------------------------------------------------------------------------
+
+ /// \brief Deduces and constructs a failure type from \p e
+ ///
+ /// \param e the failure value
+ /// \return a constructed failure value
+ template <typename E>
+ RESULT_WARN_UNUSED
+ constexpr auto fail(E&& e)
+ noexcept(std::is_nothrow_constructible<typename std::decay<E>::type,E>::value)
+ -> failure<typename std::decay<E>::type>;
+
+ /// \brief Deduces a failure reference from a reverence_wrapper
+ ///
+ /// \param e the failure value
+ /// \return a constructed failure reference
+ template <typename E>
+ RESULT_WARN_UNUSED
+ constexpr auto fail(std::reference_wrapper<E> e)
+ noexcept -> failure<E&>;
+
+ /// \brief Constructs a failure type from a series of arguments
+ ///
+ /// \tparam E the failure type
+ /// \param args the arguments to forward to E's constructor
+ /// \return a constructed failure type
+ template <typename E, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,Args...>::value>::type>
+ RESULT_WARN_UNUSED
+ constexpr auto fail(Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ -> failure<E>;
+
+ /// \brief Constructs a failure type from an initializer list and series of
+ /// arguments
+ ///
+ /// \tparam E the failure type
+ /// \param args the arguments to forward to E's constructor
+ /// \return a constructed failure type
+ template <typename E, typename U, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,std::initializer_list<U>,Args...>::value>::type>
+ RESULT_WARN_UNUSED
+ constexpr auto fail(std::initializer_list<U> ilist, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value)
+ -> failure<E>;
+
+ /// \brief Swaps the contents of two failure values
+ ///
+ /// \param lhs the left failure
+ /// \param rhs the right failure
+ template <typename E>
+ auto swap(failure<E>& lhs, failure<E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_swappable<E>::value) -> void;
+#else
+ noexcept(std::is_nothrow_move_constructible<E>::value) -> void;
+#endif
+
+ namespace detail {
+
+ //=========================================================================
+ // class : unit
+ //=========================================================================
+
+ /// \brief A standalone monostate object (effectively std::monostate). This
+ /// exists to allow for `void` specializations
+ struct unit {};
+
+ //=========================================================================
+ // non-member functions : class : unit
+ //=========================================================================
+
+ constexpr auto operator==(unit, unit) noexcept -> bool { return true; }
+ constexpr auto operator!=(unit, unit) noexcept -> bool { return false; }
+ constexpr auto operator<(unit, unit) noexcept -> bool { return false; }
+ constexpr auto operator>(unit, unit) noexcept -> bool { return false; }
+ constexpr auto operator<=(unit, unit) noexcept -> bool { return true; }
+ constexpr auto operator>=(unit, unit) noexcept -> bool { return true; }
+
+ //=========================================================================
+ // class : detail::result_union<T, E, IsTrivial>
+ //=========================================================================
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief A basic utility that acts as a union containing the T and E
+ /// types
+ ///
+ /// This is specialized on the case that both T and E are trivial, in which
+ /// case `result_union` is also trivial
+ ///
+ /// \tparam T the value type result to be returned
+ /// \tparam E the error type returned on failure
+ /// \tparam IsTrivial Whether or not both T and E are trivial
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename E,
+ bool IsTrivial = std::is_trivially_destructible<T>::value &&
+ std::is_trivially_destructible<E>::value>
+ struct result_union
+ {
+ //-----------------------------------------------------------------------
+ // Public Member Types
+ //-----------------------------------------------------------------------
+
+ using underlying_value_type = wrapped_result_type<T>;
+ using underlying_error_type = E;
+
+ //-----------------------------------------------------------------------
+ // Constructors / Assignment
+ //-----------------------------------------------------------------------
+
+ /// \brief Constructs an empty object
+ ///
+ /// This is for use with conversion constructors, since it allows a
+ /// temporary unused object to be set
+ result_union(unit) noexcept;
+
+ /// \brief Constructs the underlying value from the specified \p args
+ ///
+ /// \param args the arguments to forward to T's constructor
+ template <typename...Args>
+ constexpr result_union(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value);
+
+ /// \brief Constructs the underlying error from the specified \p args
+ ///
+ /// \param args the arguments to forward to E's constructor
+ template <typename...Args>
+ constexpr result_union(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ result_union(const result_union&) = default;
+ result_union(result_union&&) = default;
+
+ //-----------------------------------------------------------------------
+
+ auto operator=(const result_union&) -> result_union& = default;
+ auto operator=(result_union&&) -> result_union& = default;
+
+ //-----------------------------------------------------------------------
+ // Modifiers
+ //-----------------------------------------------------------------------
+
+ /// \brief A no-op for trivial types
+ auto destroy() const noexcept -> void;
+
+ //-----------------------------------------------------------------------
+ // Public Members
+ //-----------------------------------------------------------------------
+
+ union {
+ underlying_value_type m_value;
+ underlying_error_type m_error;
+ unit m_empty;
+ };
+ bool m_has_value;
+ };
+
+ //-------------------------------------------------------------------------
+
+ template <typename T, typename E>
+ struct result_union<T, E, false>
+ {
+ //-----------------------------------------------------------------------
+ // Public Member Types
+ //-----------------------------------------------------------------------
+
+ using underlying_value_type = wrapped_result_type<T>;
+ using underlying_error_type = E;
+
+ //-----------------------------------------------------------------------
+ // Constructors / Assignment / Destructor
+ //-----------------------------------------------------------------------
+
+ /// \brief Constructs an empty object
+ ///
+ /// This is for use with conversion constructors, since it allows a
+ /// temporary unused object to be set
+ result_union(unit) noexcept;
+
+ /// \brief Constructs the underlying value from the specified \p args
+ ///
+ /// \param args the arguments to forward to T's constructor
+ template <typename...Args>
+ constexpr result_union(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value);
+
+ /// \brief Constructs the underlying error from the specified \p args
+ ///
+ /// \param args the arguments to forward to E's constructor
+ template <typename...Args>
+ constexpr result_union(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ result_union(const result_union&) = default;
+ result_union(result_union&&) = default;
+
+ //-----------------------------------------------------------------------
+
+ /// \brief Destroys the underlying stored object
+ ~result_union()
+ noexcept(std::is_nothrow_destructible<T>::value &&
+ std::is_nothrow_destructible<E>::value);
+
+ //-----------------------------------------------------------------------
+
+ auto operator=(const result_union&) -> result_union& = default;
+ auto operator=(result_union&&) -> result_union& = default;
+
+ //-----------------------------------------------------------------------
+ // Modifiers
+ //-----------------------------------------------------------------------
+
+ /// \brief Destroys the underlying stored object
+ auto destroy() -> void;
+
+ //-----------------------------------------------------------------------
+ // Public Members
+ //-----------------------------------------------------------------------
+
+ union {
+ underlying_value_type m_value;
+ underlying_error_type m_error;
+ unit m_empty;
+ };
+ bool m_has_value;
+ };
+
+ //=========================================================================
+ // class : result_construct_base<T, E>
+ //=========================================================================
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// \brief Base class of assignment to enable construction and assignment
+ ///
+ /// This class is used with several pieces of construction to ensure
+ /// trivial constructibility and assignability:
+ ///
+ /// * `result_trivial_copy_ctor_base`
+ /// * `result_trivial_move_ctor_base`
+ /// * `result_copy_assign_base`
+ /// * `result_move_assign_base`
+ ///
+ /// \tparam T the value type
+ /// \tparam E the error type
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename E>
+ struct result_construct_base
+ {
+ //-----------------------------------------------------------------------
+ // Constructors / Assignment
+ //-----------------------------------------------------------------------
+
+ /// \brief Constructs an empty object
+ ///
+ /// This is for use with conversion constructors, since it allows a
+ /// temporary unused object to be set
+ result_construct_base(unit) noexcept;
+
+ /// \brief Constructs the underlying value from the specified \p args
+ ///
+ /// \param args the arguments to forward to T's constructor
+ template <typename...Args>
+ constexpr result_construct_base(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value);
+
+ /// \brief Constructs the underlying error from the specified \p args
+ ///
+ /// \param args the arguments to forward to E's constructor
+ template <typename...Args>
+ constexpr result_construct_base(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ result_construct_base(const result_construct_base&) = default;
+ result_construct_base(result_construct_base&&) = default;
+
+ auto operator=(const result_construct_base&) -> result_construct_base& = default;
+ auto operator=(result_construct_base&&) -> result_construct_base& = default;
+
+ //-----------------------------------------------------------------------
+ // Construction / Assignment
+ //-----------------------------------------------------------------------
+
+ /// \brief Constructs the value type from \p args
+ ///
+ /// \note This is an implementation detail only meant to be used during
+ /// construction
+ ///
+ /// \pre there is no contained value or error at the time of construction
+ ///
+ /// \param args the arguments to forward to T's constructor
+ template <typename...Args>
+ auto construct_value(Args&&...args)
+ noexcept(std::is_nothrow_constructible<T,Args...>::value) -> void;
+
+ /// \brief Constructs the error type from \p args
+ ///
+ /// \note This is an implementation detail only meant to be used during
+ /// construction
+ ///
+ /// \pre there is no contained value or error at the time of construction
+ ///
+ /// \param args the arguments to forward to E's constructor
+ template <typename...Args>
+ auto construct_error(Args&&...args)
+ noexcept(std::is_nothrow_constructible<E,Args...>::value) -> void;
+
+ /// \brief Constructs the underlying error from the \p other result
+ ///
+ /// If \p other contains a value, then the T type will be
+ /// default-constructed.
+ ///
+ /// \note This is an implementation detail only meant to be used during
+ /// construction of `result<void, E>` types
+ ///
+ /// \pre there is no contained value or error at the time of construction
+ ///
+ /// \param other the other result to construct
+ template <typename Result>
+ auto construct_error_from_result(Result&& other) -> void;
+
+ /// \brief Constructs the underlying type from a result object
+ ///
+ /// \note This is an implementation detail only meant to be used during
+ /// construction
+ ///
+ /// \pre there is no contained value or error at the time of construction
+ ///
+ /// \param other the other result to construct
+ template <typename Result>
+ auto construct_from_result(Result&& other) -> void;
+
+ //-----------------------------------------------------------------------
+
+ template <typename Value>
+ auto assign_value(Value&& value)
+ noexcept(std::is_nothrow_assignable<T, Value>::value) -> void;
+
+ template <typename Error>
+ auto assign_error(Error&& error)
+ noexcept(std::is_nothrow_assignable<E, Error>::value) -> void;
+
+ template <typename Result>
+ auto assign_from_result(Result&& other) -> void;
+
+ //-----------------------------------------------------------------------
+
+ template <typename ReferenceWrapper>
+ auto construct_value_from_result_impl(std::true_type, ReferenceWrapper&& reference)
+ noexcept -> void;
+
+ template <typename Value>
+ auto construct_value_from_result_impl(std::false_type, Value&& value)
+ noexcept(std::is_nothrow_constructible<T,Value>::value) -> void;
+
+ template <typename Result>
+ auto assign_value_from_result_impl(std::true_type, Result&& other) -> void;
+
+ template <typename Result>
+ auto assign_value_from_result_impl(std::false_type, Result&& other) -> void;
+
+ //-----------------------------------------------------------------------
+ // Public Members
+ //-----------------------------------------------------------------------
+
+ using storage_type = result_union<T, E>;
+
+ storage_type storage;
+ };
+
+ //=========================================================================
+ // class : result_trivial_copy_ctor_base
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct result_trivial_copy_ctor_base_impl : result_construct_base<T,E>
+ {
+ using base_type = result_construct_base<T,E>;
+ using base_type::base_type;
+
+ result_trivial_copy_ctor_base_impl(const result_trivial_copy_ctor_base_impl& other)
+ noexcept(std::is_nothrow_copy_constructible<T>::value &&
+ std::is_nothrow_copy_constructible<E>::value);
+ result_trivial_copy_ctor_base_impl(result_trivial_copy_ctor_base_impl&& other) = default;
+
+ auto operator=(const result_trivial_copy_ctor_base_impl& other) -> result_trivial_copy_ctor_base_impl& = default;
+ auto operator=(result_trivial_copy_ctor_base_impl&& other) -> result_trivial_copy_ctor_base_impl& = default;
+ };
+
+ template <bool Condition, typename Base>
+ using conditionally_nest_type = typename std::conditional<
+ Condition,
+ typename Base::base_type,
+ Base
+ >::type;
+
+ template <typename T, typename E>
+ using result_trivial_copy_ctor_base = conditionally_nest_type<
+ std::is_trivially_copy_constructible<T>::value &&
+ std::is_trivially_copy_constructible<E>::value,
+ result_trivial_copy_ctor_base_impl<T,E>
+ >;
+
+ //=========================================================================
+ // class : result_trivial_move_ctor_base
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct result_trivial_move_ctor_base_impl : result_trivial_copy_ctor_base<T,E>
+ {
+ using base_type = result_trivial_copy_ctor_base<T,E>;
+ using base_type::base_type;
+
+ result_trivial_move_ctor_base_impl(const result_trivial_move_ctor_base_impl& other) = default;
+ result_trivial_move_ctor_base_impl(result_trivial_move_ctor_base_impl&& other)
+ noexcept(std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_constructible<E>::value);
+
+ auto operator=(const result_trivial_move_ctor_base_impl& other) -> result_trivial_move_ctor_base_impl& = default;
+ auto operator=(result_trivial_move_ctor_base_impl&& other) -> result_trivial_move_ctor_base_impl& = default;
+ };
+
+ template <typename T, typename E>
+ using result_trivial_move_ctor_base = conditionally_nest_type<
+ std::is_trivially_move_constructible<T>::value &&
+ std::is_trivially_move_constructible<E>::value,
+ result_trivial_move_ctor_base_impl<T,E>
+ >;
+
+ //=========================================================================
+ // class : result_trivial_copy_assign_base
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct result_trivial_copy_assign_base_impl
+ : result_trivial_move_ctor_base<T, E>
+ {
+ using base_type = result_trivial_move_ctor_base<T,E>;
+ using base_type::base_type;
+
+ result_trivial_copy_assign_base_impl(const result_trivial_copy_assign_base_impl& other) = default;
+ result_trivial_copy_assign_base_impl(result_trivial_copy_assign_base_impl&& other) = default;
+
+ auto operator=(const result_trivial_copy_assign_base_impl& other)
+ noexcept(std::is_nothrow_copy_constructible<T>::value &&
+ std::is_nothrow_copy_constructible<E>::value &&
+ std::is_nothrow_copy_assignable<T>::value &&
+ std::is_nothrow_copy_assignable<E>::value)
+ -> result_trivial_copy_assign_base_impl&;
+ auto operator=(result_trivial_copy_assign_base_impl&& other)
+ -> result_trivial_copy_assign_base_impl& = default;
+ };
+
+ template <typename T, typename E>
+ using result_trivial_copy_assign_base = conditionally_nest_type<
+ std::is_trivially_copy_constructible<T>::value &&
+ std::is_trivially_copy_constructible<E>::value &&
+ std::is_trivially_copy_assignable<T>::value &&
+ std::is_trivially_copy_assignable<E>::value &&
+ std::is_trivially_destructible<T>::value &&
+ std::is_trivially_destructible<E>::value,
+ result_trivial_copy_assign_base_impl<T,E>
+ >;
+
+ //=========================================================================
+ // class : result_trivial_move_assign_base
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct result_trivial_move_assign_base_impl
+ : result_trivial_copy_assign_base<T, E>
+ {
+ using base_type = result_trivial_copy_assign_base<T,E>;
+ using base_type::base_type;
+
+ result_trivial_move_assign_base_impl(const result_trivial_move_assign_base_impl& other) = default;
+ result_trivial_move_assign_base_impl(result_trivial_move_assign_base_impl&& other) = default;
+
+ auto operator=(const result_trivial_move_assign_base_impl& other)
+ -> result_trivial_move_assign_base_impl& = default;
+ auto operator=(result_trivial_move_assign_base_impl&& other)
+ noexcept(std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_constructible<E>::value &&
+ std::is_nothrow_move_assignable<T>::value &&
+ std::is_nothrow_move_assignable<E>::value)
+ -> result_trivial_move_assign_base_impl&;
+ };
+
+ template <typename T, typename E>
+ using result_trivial_move_assign_base = conditionally_nest_type<
+ std::is_trivially_move_constructible<T>::value &&
+ std::is_trivially_move_constructible<E>::value &&
+ std::is_trivially_move_assignable<T>::value &&
+ std::is_trivially_move_assignable<E>::value &&
+ std::is_trivially_destructible<T>::value &&
+ std::is_trivially_destructible<E>::value,
+ result_trivial_move_assign_base_impl<T,E>
+ >;
+
+ //=========================================================================
+ // class : disable_copy_ctor
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct disable_copy_ctor : result_trivial_move_assign_base<T,E>
+ {
+ using base_type = result_trivial_move_assign_base<T,E>;
+ using base_type::base_type;
+
+ disable_copy_ctor(const disable_copy_ctor& other) = delete;
+ disable_copy_ctor(disable_copy_ctor&& other) = default;
+
+ auto operator=(const disable_copy_ctor& other)
+ -> disable_copy_ctor& = default;
+ auto operator=(disable_copy_ctor&& other)
+ -> disable_copy_ctor& = default;
+ };
+
+ template <typename T, typename E>
+ using result_copy_ctor_base = conditionally_nest_type<
+ std::is_copy_constructible<T>::value &&
+ std::is_copy_constructible<E>::value,
+ disable_copy_ctor<T,E>
+ >;
+
+ //=========================================================================
+ // class : disable_move_ctor
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct disable_move_ctor : result_copy_ctor_base<T,E>
+ {
+ using base_type = result_copy_ctor_base<T,E>;
+ using base_type::base_type;
+
+ disable_move_ctor(const disable_move_ctor& other) = default;
+ disable_move_ctor(disable_move_ctor&& other) = delete;
+
+ auto operator=(const disable_move_ctor& other)
+ -> disable_move_ctor& = default;
+ auto operator=(disable_move_ctor&& other)
+ -> disable_move_ctor& = default;
+ };
+
+ template <typename T, typename E>
+ using result_move_ctor_base = conditionally_nest_type<
+ std::is_move_constructible<T>::value &&
+ std::is_move_constructible<E>::value,
+ disable_move_ctor<T,E>
+ >;
+
+ //=========================================================================
+ // class : disable_move_assignment
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct disable_move_assignment
+ : result_move_ctor_base<T, E>
+ {
+ using base_type = result_move_ctor_base<T, E>;
+ using base_type::base_type;
+
+ disable_move_assignment(const disable_move_assignment& other) = default;
+ disable_move_assignment(disable_move_assignment&& other) = default;
+
+ auto operator=(const disable_move_assignment& other)
+ -> disable_move_assignment& = delete;
+ auto operator=(disable_move_assignment&& other)
+ -> disable_move_assignment& = default;
+ };
+
+ template <typename T, typename E>
+ using result_copy_assign_base = conditionally_nest_type<
+ std::is_nothrow_copy_constructible<T>::value &&
+ std::is_nothrow_copy_constructible<E>::value &&
+ std::is_copy_assignable<wrapped_result_type<T>>::value &&
+ std::is_copy_assignable<E>::value,
+ disable_move_assignment<T,E>
+ >;
+
+ //=========================================================================
+ // class : disable_copy_assignment
+ //=========================================================================
+
+ template <typename T, typename E>
+ struct disable_copy_assignment
+ : result_copy_assign_base<T, E>
+ {
+ using base_type = result_copy_assign_base<T, E>;
+ using base_type::base_type;
+
+ disable_copy_assignment(const disable_copy_assignment& other) = default;
+ disable_copy_assignment(disable_copy_assignment&& other) = default;
+
+ auto operator=(const disable_copy_assignment& other)
+ -> disable_copy_assignment& = default;
+ auto operator=(disable_copy_assignment&& other)
+ -> disable_copy_assignment& = delete;
+ };
+
+ template <typename T, typename E>
+ using result_move_assign_base = conditionally_nest_type<
+ std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_constructible<E>::value &&
+ std::is_move_assignable<wrapped_result_type<T>>::value &&
+ std::is_move_assignable<E>::value,
+ disable_copy_assignment<T,E>
+ >;
+
+ //=========================================================================
+ // alias : result_storage
+ //=========================================================================
+
+ template <typename T, typename E>
+ using result_storage = result_move_assign_base<T, E>;
+
+ //=========================================================================
+ // traits : result
+ //=========================================================================
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_convertible = std::integral_constant<bool,(
+ // T1 constructible from result<T2,E2>
+ std::is_constructible<T1, result<T2,E2>&>:: value ||
+ std::is_constructible<T1, const result<T2,E2>&>:: value ||
+ std::is_constructible<T1, result<T2,E2>&&>:: value ||
+ std::is_constructible<T1, const result<T2,E2>&&>:: value ||
+
+ // E1 constructible from result<T2,E2>
+ std::is_constructible<E1, result<T2,E2>&>:: value ||
+ std::is_constructible<E1, const result<T2,E2>&>:: value ||
+ std::is_constructible<E1, result<T2,E2>&&>:: value ||
+ std::is_constructible<E1, const result<T2,E2>&&>:: value ||
+
+ // result<T2,E2> convertible to T1
+ std::is_convertible<result<T2,E2>&, T1>:: value ||
+ std::is_convertible<const result<T2,E2>&, T1>:: value ||
+ std::is_convertible<result<T2,E2>&&, T1>::value ||
+ std::is_convertible<const result<T2,E2>&&, T1>::value ||
+
+ // result<T2,E2> convertible to E2
+ std::is_convertible<result<T2,E2>&, E1>:: value ||
+ std::is_convertible<const result<T2,E2>&, E1>:: value ||
+ std::is_convertible<result<T2,E2>&&, E1>::value ||
+ std::is_convertible<const result<T2,E2>&&, E1>::value
+ )>;
+
+ //-------------------------------------------------------------------------
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_copy_convertible = std::integral_constant<bool,(
+ !result_is_convertible<T1,E1,T2,E2>::value &&
+ std::is_constructible<T1, const T2&>::value &&
+ std::is_constructible<E1, const E2&>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_implicit_copy_convertible = std::integral_constant<bool,(
+ result_is_copy_convertible<T1,E1,T2,E2>::value &&
+ std::is_convertible<const T2&, T1>::value &&
+ std::is_convertible<const E2&, E1>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_explicit_copy_convertible = std::integral_constant<bool,(
+ result_is_copy_convertible<T1,E1,T2,E2>::value &&
+ (!std::is_convertible<const T2&, T1>::value ||
+ !std::is_convertible<const E2&, E1>::value)
+ )>;
+
+ //-------------------------------------------------------------------------
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_move_convertible = std::integral_constant<bool,(
+ !result_is_convertible<T1,E1,T2,E2>::value &&
+ std::is_constructible<T1, T2&&>::value &&
+ std::is_constructible<E1, E2&&>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_implicit_move_convertible = std::integral_constant<bool,(
+ result_is_move_convertible<T1,E1,T2,E2>::value &&
+ std::is_convertible<T2&&, T1>::value &&
+ std::is_convertible<E2&&, E1>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_explicit_move_convertible = std::integral_constant<bool,(
+ result_is_move_convertible<T1,E1,T2,E2>::value &&
+ (!std::is_convertible<T2&&, T1>::value ||
+ !std::is_convertible<E2&&, E1>::value)
+ )>;
+
+ //-------------------------------------------------------------------------
+
+ template <typename T, typename U>
+ using result_is_value_convertible = std::integral_constant<bool,(
+ std::is_constructible<T, U&&>::value &&
+ !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
+ !std::is_same<typename std::decay<U>::type, in_place_error_t>::value &&
+ !is_result<typename std::decay<U>::type>::value
+ )>;
+
+ template <typename T, typename U>
+ using result_is_explicit_value_convertible = std::integral_constant<bool,(
+ result_is_value_convertible<T, U>::value &&
+ !std::is_convertible<U&&, T>::value
+ )>;
+
+ template <typename T, typename U>
+ using result_is_implicit_value_convertible = std::integral_constant<bool,(
+ result_is_value_convertible<T, U>::value &&
+ std::is_convertible<U&&, T>::value
+ )>;
+
+ //-------------------------------------------------------------------------
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_convert_assignable = std::integral_constant<bool,(
+ result_is_convertible<T1,E1,T2,E2>::value &&
+
+ std::is_assignable<T1&, result<T2,E2>&>::value &&
+ std::is_assignable<T1&, const result<T2,E2>&>::value &&
+ std::is_assignable<T1&, result<T2,E2>&&>::value &&
+ std::is_assignable<T1&, const result<T2,E2>&&>::value &&
+
+ std::is_assignable<E1&, result<T2,E2>&>::value &&
+ std::is_assignable<E1&, const result<T2,E2>&>::value &&
+ std::is_assignable<E1&, result<T2,E2>&&>::value &&
+ std::is_assignable<E1&, const result<T2,E2>&&>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_copy_convert_assignable = std::integral_constant<bool,(
+ !result_is_convert_assignable<T1,E1,T2,E2>::value &&
+
+ std::is_nothrow_constructible<T1, const T2&>::value &&
+ std::is_assignable<wrapped_result_type<T1>&, const T2&>::value &&
+ std::is_nothrow_constructible<E1, const E2&>::value &&
+ std::is_assignable<E1&, const E2&>::value
+ )>;
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ using result_is_move_convert_assignable = std::integral_constant<bool,(
+ !result_is_convert_assignable<T1,E1,T2,E2>::value &&
+
+ std::is_nothrow_constructible<T1, T2&&>::value &&
+ std::is_assignable<T1&, T2&&>::value &&
+ std::is_nothrow_constructible<E1, E2&&>::value &&
+ std::is_assignable<E1&, E2&&>::value
+ )>;
+
+ //-------------------------------------------------------------------------
+
+ template <typename T, typename U>
+ using result_is_value_assignable = std::integral_constant<bool,(
+ !is_result<typename std::decay<U>::type>::value &&
+ !is_failure<typename std::decay<U>::type>::value &&
+ std::is_nothrow_constructible<T,U>::value &&
+ std::is_assignable<wrapped_result_type<T>&,U>::value &&
+ (
+ !std::is_same<typename std::decay<U>::type,typename std::decay<T>::type>::value ||
+ !std::is_scalar<T>::value
+ )
+ )>;
+
+ template <typename E, typename E2>
+ using result_is_failure_assignable = std::integral_constant<bool,(
+ std::is_nothrow_constructible<E,E2>::value &&
+ std::is_assignable<E&,E2>::value
+ )>;
+
+ // Friending 'extract_error" below was causing some compilers to incorrectly
+ // identify `exp.m_storage.m_error` as being an access violation despite the
+ // friendship. Using a type name instead seems to be ubiquitous across
+ // compilers
+ struct result_error_extractor
+ {
+ template <typename T, typename E>
+ static constexpr auto get(const result<T,E>& exp) noexcept -> const E&;
+ template <typename T, typename E>
+ static constexpr auto get(result<T,E>& exp) noexcept -> E&;
+ };
+
+ template <typename T, typename E>
+ constexpr auto extract_error(const result<T,E>& exp) noexcept -> const E&;
+
+ template <typename E>
+ [[noreturn]]
+ auto throw_bad_result_access(E&& error) -> void;
+
+ template <typename String, typename E>
+ [[noreturn]]
+ auto throw_bad_result_access_message(String&& message, E&& error) -> void;
+
+ } // namespace detail
+
+ /////////////////////////////////////////////////////////////////////////////
+ /// \brief The class template `result` manages result results from APIs,
+ /// while encoding possible failure conditions.
+ ///
+ /// A common use-case for result is the return value of a function that
+ /// may fail. As opposed to other approaches, such as `std::pair<T,bool>`
+ /// or `std::optional`, `result` more accurately conveys the intent of the
+ /// user along with the failure condition to the caller. This effectively
+ /// produces an orthogonal error handling mechanism that allows for exception
+ /// safety while also allowing discrete testability of the return type.
+ ///
+ /// `result<T,E>` types may contain a `T` value, which signifies that an
+ /// operation succeeded in producing the result value of type `T`. If an
+ /// `result` does not contain a `T` value, it will always contain an `E`
+ /// error condition instead.
+ ///
+ /// An `result<T,E>` can always be queried for a possible error case by
+ /// calling the `error()` function, even if it contains a value.
+ /// In the case that a `result<T,E>` contains a value object, this will
+ /// simply return an `E` object constructed through default aggregate
+ /// construction, as if through the expression `E{}`, which is assumed to be
+ /// a "valid" (no-error) state for an `E` type.
+ /// For example:
+ ///
+ /// * `std::error_code{}` produces a default-construct error-code, which is
+ /// the "no error" state,
+ /// * integral (or enum) error codes produce a `0` value (no error), thanks to
+ /// zero-initialization,
+ /// * `std::exception_ptr{}` produces a null-pointer,
+ /// * `std::string{}` produces an empty string `""`,
+ /// * etc.
+ ///
+ /// When a `result<T,E>` contains either a value or error, the storage for
+ /// that object is guaranteed to be allocated as part of the result
+ /// object's footprint, i.e. no dynamic memory allocation ever takes place.
+ /// Thus, a result object models an object, not a pointer, even though the
+ /// `operator*()` and `operator->()` are defined.
+ ///
+ /// When an object of type `result<T,E>` is contextually converted to
+ /// `bool`, the conversion returns `true` if the object contains a value and
+ /// `false` if it contains an error.
+ ///
+ /// `result` objects do not have a "valueless" state like `variant`s do.
+ /// Once a `result` has been constructed with a value or error, the
+ /// active underlying type can only be changed through assignment which may
+ /// is only enabled if construction is guaranteed to be *non-throwing*. This
+ /// ensures that a valueless state cannot occur naturally.
+ ///
+ /// Example Use:
+ /// \code
+ /// auto to_string(int x) -> result<std::string>
+ /// {
+ /// try {
+ /// return std::stoi(x);
+ /// } catch (const std::invalid_argument&) {
+ /// return fail(std::errc::invalid_argument);
+ /// } catch (const std::std::out_of_range&) {
+ /// return fail(std::errc::result_out_of_range);
+ /// }
+ /// }
+ /// \endcode
+ ///
+ /// \note If using C++17 or above, `fail` can be replaced with
+ /// `failure{...}` thanks to CTAD.
+ ///
+ /// \tparam T the underlying value type
+ /// \tparam E the underlying error type
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename E>
+ class RESULT_NODISCARD result
+ {
+ // Type requirements
+
+ static_assert(
+ !std::is_abstract<T>::value,
+ "It is ill-formed for T to be abstract type"
+ );
+ static_assert(
+ !std::is_same<typename std::decay<T>::type, in_place_t>::value,
+ "It is ill-formed for T to be a (possibly CV-qualified) in_place_t type"
+ );
+ static_assert(
+ !is_result<typename std::decay<T>::type>::value,
+ "It is ill-formed for T to be a (possibly CV-qualified) 'result' type"
+ );
+ static_assert(
+ !is_failure<typename std::decay<T>::type>::value,
+ "It is ill-formed for T to be a (possibly CV-qualified) 'failure' type"
+ );
+ static_assert(
+ !std::is_rvalue_reference<T>::value,
+ "It is ill-formed for T to be an rvalue 'result type. "
+ "Only lvalue references are valid."
+ );
+
+ static_assert(
+ !std::is_abstract<E>::value,
+ "It is ill-formed for E to be abstract type"
+ );
+ static_assert(
+ !std::is_void<typename std::decay<E>::type>::value,
+ "It is ill-formed for E to be (possibly CV-qualified) void type"
+ );
+ static_assert(
+ !is_result<typename std::decay<E>::type>::value,
+ "It is ill-formed for E to be a (possibly CV-qualified) 'result' type"
+ );
+ static_assert(
+ !is_failure<typename std::decay<E>::type>::value,
+ "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type"
+ );
+ static_assert(
+ !std::is_same<typename std::decay<E>::type, in_place_t>::value,
+ "It is ill-formed for E to be a (possibly CV-qualified) in_place_t type"
+ );
+ static_assert(
+ !std::is_reference<E>::value,
+ "It is ill-formed for E to be a reference type. "
+ "Only T types may be lvalue references"
+ );
+
+ // Friendship
+
+ friend detail::result_error_extractor;
+
+ template <typename T2, typename E2>
+ friend class result;
+
+ //-------------------------------------------------------------------------
+ // Public Member Types
+ //-------------------------------------------------------------------------
+ public:
+
+ using value_type = T; ///< The value type of this result
+ using error_type = E; ///< The error type of this result
+ using failure_type = failure<E>; ///< The failure type
+
+ template <typename U>
+ using rebind = result<U,E>; ///< Rebinds the result type
+
+ //-------------------------------------------------------------------------
+ // Constructor / Destructor / Assignment
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \brief Default-constructs a result with the underlying value type
+ /// active
+ ///
+ /// This constructor is only enabled if `T` is default-constructible
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// assert(cpp::result<std::string,int>{} == std::string{});
+ /// ```
+ template <typename U=T,
+ typename = typename std::enable_if<std::is_constructible<U>::value>::type>
+ constexpr result()
+ noexcept(std::is_nothrow_constructible<U>::value);
+
+ /// \brief Copy constructs this result
+ ///
+ /// If \p other contains a value, initializes the contained value as if
+ /// direct-initializing (but not direct-list-initializing) an object of
+ /// type `T` with the expression *other.
+ ///
+ /// If other contains an error, constructs an object that contains a copy
+ /// of that error.
+ ///
+ /// \note This constructor is defined as deleted if
+ /// `std::is_copy_constructible<T>::value` or
+ /// `std::is_copy_constructible<E>::value` is `false`
+ ///
+ /// \note This constructor is defined as trivial if both
+ /// `std::is_trivially_copy_constructible<T>::value` and
+ /// `std::is_trivially_copy_constructible<E>::value` are `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// const auto r = cpp::result<int,int>{42};
+ /// const auto s = r;
+ ///
+ /// assert(r == s);
+ /// ```
+ ///
+ /// \param other the result to copy
+ constexpr result(const result& other) = default;
+
+ /// \brief Move constructs a result
+ ///
+ /// If other contains a value, initializes the contained value as if
+ /// direct-initializing (but not direct-list-initializing) an object
+ /// of type T with the expression `std::move(*other)` and does not make
+ /// other empty: a moved-from result still contains a value, but the
+ /// value itself is moved from.
+ ///
+ /// If other contains an error, move-constructs this result from that
+ /// error.
+ ///
+ /// \note This constructor is defined as deleted if
+ /// `std::is_move_constructible<T>::value` or
+ /// `std::is_move_constructible<E>::value` is `false`
+ ///
+ /// \note This constructor is defined as trivial if both
+ /// `std::is_trivially_move_constructible<T>::value` and
+ /// `std::is_trivially_move_constructible<E>::value` are `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<std::string,int>{"hello world"};
+ /// auto s = std::move(r);
+ ///
+ /// assert(s == "hello world");
+ /// ```
+ ///
+ /// \param other the result to move
+ constexpr result(result&& other) = default;
+
+ /// \{
+ /// \brief Converting copy constructor
+ ///
+ /// If \p other contains a value, constructs a result object
+ /// that contains a value, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type `T` with the
+ /// expression `*other`.
+ ///
+ /// If \p other contains an error, constructs a result object that
+ /// contains an error, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type `E`.
+ ///
+ /// \note This constructor does not participate in overload resolution
+ /// unless the following conditions are met:
+ /// - `std::is_constructible_v<T, const U&>` is `true`
+ /// - T is not constructible or convertible from any expression
+ /// of type (possibly const) `result<T2,E2>`
+ /// - E is not constructible or convertible from any expression
+ /// of type (possible const) `result<T2,E2>`
+ ///
+ /// \note This constructor is explicit if and only if
+ /// `std::is_convertible_v<const T2&, T>` or
+ /// `std::is_convertible_v<const E2&, E>` is `false`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// const auto r = cpp::result<int,int>{42};
+ /// const auto s = cpp::result<long,long>{r};
+ ///
+ /// assert(r == s);
+ /// ```
+ ///
+ /// \param other the other type to convert
+ template <typename T2, typename E2,
+ typename std::enable_if<detail::result_is_implicit_copy_convertible<T,E,T2,E2>::value,int>::type = 0>
+ result(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_constructible<T,const T2&>::value &&
+ std::is_nothrow_constructible<E,const E2&>::value);
+ template <typename T2, typename E2,
+ typename std::enable_if<detail::result_is_explicit_copy_convertible<T,E,T2,E2>::value,int>::type = 0>
+ explicit result(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_constructible<T,const T2&>::value &&
+ std::is_nothrow_constructible<E,const E2&>::value);
+ /// \}
+
+ /// \{
+ /// \brief Converting move constructor
+ ///
+ /// If \p other contains a value, constructs a result object
+ /// that contains a value, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type T with the
+ /// expression `std::move(*other)`.
+ ///
+ /// If \p other contains an error, constructs a result object that
+ /// contains an error, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type E&&.
+ ///
+ /// \note This constructor does not participate in overload resolution
+ /// unless the following conditions are met:
+ /// - `std::is_constructible_v<T, const U&>` is `true`
+ /// - T is not constructible or convertible from any expression
+ /// of type (possibly const) `result<T2,E2>`
+ /// - E is not constructible or convertible from any expression
+ /// of type (possible const) `result<T2,E2>`
+ ///
+ /// \note This constructor is explicit if and only if
+ /// `std::is_convertible_v<const T2&, T>` or
+ /// `std::is_convertible_v<const E2&, E>` is `false`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<std::unique_ptr<Derived>,int>{
+ /// std::make_unique<Derived>()
+ /// };
+ /// const auto s = cpp::result<std::unique_ptr<Base>,long>{
+ /// std::move(r)
+ /// };
+ /// ```
+ ///
+ /// \param other the other type to convert
+ template <typename T2, typename E2,
+ typename std::enable_if<detail::result_is_implicit_move_convertible<T,E,T2,E2>::value,int>::type = 0>
+ result(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_constructible<T,T2&&>::value &&
+ std::is_nothrow_constructible<E,E2&&>::value);
+ template <typename T2, typename E2,
+ typename std::enable_if<detail::result_is_explicit_move_convertible<T,E,T2,E2>::value,int>::type = 0>
+ explicit result(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_constructible<T,T2&&>::value &&
+ std::is_nothrow_constructible<E,E2&&>::value);
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Constructs a result object that contains a value
+ ///
+ /// The value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `T` from the arguments
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<std::string,int>{
+ /// cpp::in_place, "Hello world"
+ /// };
+ /// ```
+ ///
+ /// \param args the arguments to pass to T's constructor
+ template <typename...Args,
+ typename = typename std::enable_if<std::is_constructible<T,Args...>::value>::type>
+ constexpr explicit result(in_place_t, Args&&... args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value);
+
+ /// \brief Constructs a result object that contains a value
+ ///
+ /// The value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `T` from the arguments
+ /// `std::forward<std::initializer_list<U>>(ilist)`,
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<std::string,int>{
+ /// cpp::in_place, {'H','e','l','l','o'}
+ /// };
+ /// ```
+ ///
+ /// \param ilist An initializer list of entries to forward
+ /// \param args the arguments to pass to T's constructor
+ template <typename U, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<T, std::initializer_list<U>&, Args...>::value>::type>
+ constexpr explicit result(in_place_t,
+ std::initializer_list<U> ilist,
+ Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, std::initializer_list<U>, Args...>::value);
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Constructs a result object that contains an error
+ ///
+ /// the value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `E` from the arguments
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,std::string>{
+ /// cpp::in_place_error, "Hello world"
+ /// };
+ /// ```
+ ///
+ /// \param args the arguments to pass to E's constructor
+ template <typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,Args...>::value>::type>
+ constexpr explicit result(in_place_error_t, Args&&... args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ /// \brief Constructs a result object that contains an error
+ ///
+ /// The value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `E` from the arguments
+ /// `std::forward<std::initializer_list<U>>(ilist)`,
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,std::string>{
+ /// cpp::in_place_error, {'H','e','l','l','o'}
+ /// };
+ /// ```
+ ///
+ /// \param ilist An initializer list of entries to forward
+ /// \param args the arguments to pass to Es constructor
+ template <typename U, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>&, Args...>::value>::type>
+ constexpr explicit result(in_place_error_t,
+ std::initializer_list<U> ilist,
+ Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value);
+
+ //-------------------------------------------------------------------------
+
+ /// \{
+ /// \brief Constructs the underlying error of this result
+ ///
+ /// \note This constructor only participates in overload resolution if
+ /// `E` is constructible from \p e
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// cpp::result<int,int> r = cpp::fail(42);
+ ///
+ /// auto get_error_result() -> cpp::result<int,std::string> {
+ /// return cpp::fail("hello world!");
+ /// }
+ /// ```
+ ///
+ /// \param e the failure error
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,const E2&>::value>::type>
+ constexpr /* implicit */ result(const failure<E2>& e)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value);
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2&&>::value>::type>
+ constexpr /* implicit */ result(failure<E2>&& e)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value);
+ /// \}
+
+ /// \{
+ /// \brief Constructs a result object that contains a value
+ ///
+ /// The value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type T with the expression
+ /// value.
+ ///
+ /// \note This constructor is constexpr if the constructor of T
+ /// selected by direct-initialization is constexpr
+ ///
+ /// \note This constructor does not participate in overload
+ /// resolution unless `std::is_constructible_v<T, U&&>` is true
+ /// and `decay_t<U>` is neither `in_place_t`, `in_place_error_t`,
+ /// nor a `result` type.
+ ///
+ /// \note This constructor is explicit if and only if
+ /// `std::is_convertible_v<U&&, T>` is `false`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// cpp::result<int,int> r = 42;
+ ///
+ /// auto get_value() -> cpp::result<std::string,int> {
+ /// return "hello world!"; // implicit conversion
+ /// }
+ /// ```
+ ///
+ /// \param value the value to copy
+ template <typename U,
+ typename std::enable_if<detail::result_is_explicit_value_convertible<T,U>::value,int>::type = 0>
+ constexpr explicit result(U&& value)
+ noexcept(std::is_nothrow_constructible<T,U>::value);
+ template <typename U,
+ typename std::enable_if<detail::result_is_implicit_value_convertible<T,U>::value,int>::type = 0>
+ constexpr /* implicit */ result(U&& value)
+ noexcept(std::is_nothrow_constructible<T,U>::value);
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Copy assigns the result stored in \p other
+ ///
+ /// \note This assignment operator only participates in overload resolution
+ /// if the following conditions are met:
+ /// - `std::is_nothrow_copy_constructible_v<T>` is `true`, and
+ /// - `std::is_nothrow_copy_constructible_v<E>` is `true`
+ /// this restriction guarantees that no '
+ ///
+ /// \note This assignment operator is defined as trivial if the following
+ /// conditions are all `true`:
+ /// - `std::is_trivially_copy_constructible<T>::value`
+ /// - `std::is_trivially_copy_constructible<E>::value`
+ /// - `std::is_trivially_copy_assignable<T>::value`
+ /// - `std::is_trivially_copy_assignable<E>::value`
+ /// - `std::is_trivially_destructible<T>::value`
+ /// - `std::is_trivially_destructible<E>::value`
+ ///
+ /// \param other the other result to copy
+ auto operator=(const result& other) -> result& = default;
+
+ /// \brief Move assigns the result stored in \p other
+ ///
+ /// \note This assignment operator only participates in overload resolution
+ /// if the following conditions are met:
+ /// - `std::is_nothrow_copy_constructible_v<T>` is `true`, and
+ /// - `std::is_nothrow_copy_constructible_v<E>` is `true`
+ /// this restriction guarantees that no 'valueless_by_exception` state
+ /// may occur.
+ ///
+ /// \note This assignment operator is defined as trivial if the following
+ /// conditions are all `true`:
+ /// - `std::is_trivially_move_constructible<T>::value`
+ /// - `std::is_trivially_move_constructible<E>::value`
+ /// - `std::is_trivially_move_assignable<T>::value`
+ /// - `std::is_trivially_move_assignable<E>::value`
+ /// - `std::is_trivially_destructible<T>::value`
+ /// - `std::is_trivially_destructible<E>::value`
+ ///
+ /// \param other the other result to copy
+ auto operator=(result&& other) -> result& = default;
+
+ /// \brief Copy-converts the state of \p other
+ ///
+ /// If both `*this` and \p other contain either values or errors, the
+ /// underlying value is constructed as if through assignment.
+ ///
+ /// Otherwise if `*this` contains a value, but \p other contains an error,
+ /// then the contained value is destroyed by calling its destructor. `*this`
+ /// will no longer contain a value after the call, and will now contain `E`
+ /// constructed as if direct-initializing (but not direct-list-initializing)
+ /// an object with an argument of `const E2&`.
+ ///
+ /// If \p other contains a value and `*this` contains an error, then the
+ /// contained error is destroyed by calling its destructor. `*this` now
+ /// contains a value constructed as if direct-initializing (but not
+ /// direct-list-initializing) an object with an argument of `const T2&`.
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<T, const T2&>`,
+ /// `std::is_assignable_v<T&, const T2&>`,
+ /// `std::is_nothrow_constructible_v<E, const E2&>`,
+ /// `std::is_assignable_v<E&, const E2&>` are all true.
+ /// - T is not constructible, convertible, or assignable from any
+ /// expression of type (possibly const) `result<T2,E2>`
+ ///
+ /// \param other the other result object to convert
+ /// \return reference to `(*this)`
+ template <typename T2, typename E2,
+ typename = typename std::enable_if<detail::result_is_copy_convert_assignable<T,E,T2,E2>::value>::type>
+ auto operator=(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_assignable<T,const T2&>::value &&
+ std::is_nothrow_assignable<E,const E2&>::value) -> result&;
+
+ /// \brief Move-converts the state of \p other
+ ///
+ /// If both `*this` and \p other contain either values or errors, the
+ /// underlying value is constructed as if through move-assignment.
+ ///
+ /// Otherwise if `*this` contains a value, but \p other contains an error,
+ /// then the contained value is destroyed by calling its destructor. `*this`
+ /// will no longer contain a value after the call, and will now contain `E`
+ /// constructed as if direct-initializing (but not direct-list-initializing)
+ /// an object with an argument of `E2&&`.
+ ///
+ /// If \p other contains a value and `*this` contains an error, then the
+ /// contained error is destroyed by calling its destructor. `*this` now
+ /// contains a value constructed as if direct-initializing (but not
+ /// direct-list-initializing) an object with an argument of `T2&&`.
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<T, T2&&>`,
+ /// `std::is_assignable_v<T&, T2&&>`,
+ /// `std::is_nothrow_constructible_v<E, E2&&>`,
+ /// `std::is_assignable_v<E&, E2&&>` are all true.
+ /// - T is not constructible, convertible, or assignable from any
+ /// expression of type (possibly const) `result<T2,E2>`
+ ///
+ /// \param other the other result object to convert
+ /// \return reference to `(*this)`
+ template <typename T2, typename E2,
+ typename = typename std::enable_if<detail::result_is_move_convert_assignable<T,E,T2,E2>::value>::type>
+ auto operator=(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_assignable<T,T2&&>::value &&
+ std::is_nothrow_assignable<E,E2&&>::value) -> result&;
+
+ /// \brief Perfect-forwarded assignment
+ ///
+ /// Depending on whether `*this` contains a value before the call, the
+ /// contained value is either direct-initialized from std::forward<U>(value)
+ /// or assigned from std::forward<U>(value).
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::decay_t<U>` is not a result type,
+ /// - `std::decay_t<U>` is not a failure type
+ /// - `std::is_nothrow_constructible_v<T, U>` is `true`
+ /// - `std::is_assignable_v<T&, U>` is `true`
+ /// - and at least one of the following is `true`:
+ /// - `T` is not a scalar type;
+ /// - `std::decay_t<U>` is not `T`.
+ ///
+ /// \param value to assign to the contained value
+ /// \return reference to `(*this)`
+ template <typename U,
+ typename = typename std::enable_if<detail::result_is_value_assignable<T,U>::value>::type>
+ auto operator=(U&& value)
+ noexcept(std::is_nothrow_assignable<T,U>::value) -> result&;
+
+ /// \{
+ /// \brief Perfect-forwarded assignment
+ ///
+ /// Depending on whether `*this` contains an error before the call, the
+ /// contained error is either direct-initialized via forwarding the error,
+ /// or assigned from forwarding the error
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<E, E2>` is `true`, and
+ /// - `std::is_assignable_v<E&, E2>` is `true`
+ ///
+ /// \param other the failure value to assign to this
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<detail::result_is_failure_assignable<E,const E2&>::value>::type>
+ auto operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&;
+ template <typename E2,
+ typename = typename std::enable_if<detail::result_is_failure_assignable<E,E2&&>::value>::type>
+ auto operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Observers
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \{
+ /// \brief Retrieves a pointer to the contained value
+ ///
+ /// This operator exists to give `result` an `optional`-like API for cases
+ /// where it's known that the `result` already contains a value.
+ ///
+ /// Care must be taken to ensure that this is only used in safe contexts
+ /// where a `T` value is active.
+ ///
+ /// \note The behavior is undefined if `*this` does not contain a value.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<Widget,int>{
+ /// make_widget()
+ /// };
+ ///
+ /// r->do_something();
+ /// ```
+ ///
+ /// \return a pointer to the contained value
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto operator->()
+ noexcept -> typename std::remove_reference<T>::type*;
+ RESULT_WARN_UNUSED
+ constexpr auto operator->()
+ const noexcept -> typename std::remove_reference<typename std::add_const<T>::type>::type*;
+ /// \}
+
+ /// \{
+ /// \brief Retrieves a reference to the contained value
+ ///
+ /// This operator exists to give `result` an `optional`-like API for cases
+ /// where it's known that the `result` already contains a value.
+ ///
+ /// Care must be taken to ensure that this is only used in safe contexts
+ /// where a `T` value is active.
+ ///
+ /// \note The behaviour is undefined if `*this` does not contain a value
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<Widget,int>{
+ /// make_widget()
+ /// };
+ ///
+ /// (*r).do_something();
+ ///
+ /// consume(*r);
+ /// ```
+ ///
+ /// \return a reference to the contained value
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto operator*()
+ & noexcept -> typename std::add_lvalue_reference<T>::type;
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto operator*()
+ && noexcept -> typename std::add_rvalue_reference<T>::type;
+ RESULT_WARN_UNUSED
+ constexpr auto operator*()
+ const& noexcept -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type;
+ RESULT_WARN_UNUSED
+ constexpr auto operator*()
+ const&& noexcept -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Contextually convertible to `true` if `*this` contains a value
+ ///
+ /// This function exists to allow for simple, terse checks for containing
+ /// a value.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto get_result() -> cpp::result<int, int>;
+ /// auto r = get_result();
+ /// if (r) { ... }
+ ///
+ /// assert(static_cast<bool>(cpp::result<int,int>{42}));
+ ///
+ /// assert(!static_cast<bool>(cpp::result<int,int>{cpp::fail(42)}));
+ /// ```
+ ///
+ /// \return `true` if `*this` contains a value, `false` if `*this`
+ /// does not contain a value
+ RESULT_WARN_UNUSED
+ constexpr explicit operator bool() const noexcept;
+
+ /// \brief Returns `true` if `*this` contains a value
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto get_result() -> cpp::result<int, int>;
+ /// auto r = get_result();
+ /// if (r.has_value()) { ... }
+ ///
+ /// assert(cpp::result<int,int>{42}.has_value());
+ ///
+ /// assert(!cpp::result<int,int>{cpp::fail(42)}.has_value());
+ /// ```
+ ///
+ /// \return `true` if `*this` contains a value, `false` if `*this`
+ /// contains an error
+ RESULT_WARN_UNUSED
+ constexpr auto has_value() const noexcept -> bool;
+
+ /// \brief Returns `true` if `*this` contains an error
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto get_result() -> cpp::result<int, int>;
+ ///
+ /// auto r = get_result();
+ /// if (r.has_error()) { ... }
+ ///
+ /// assert(!cpp::result<int,int>{42}.has_error());
+ ///
+ /// assert(cpp::result<int,int>{cpp::fail(42)}.has_error());
+ /// ```
+ ///
+ /// \return `true` if `*this` contains an error, `false` if `*this`
+ /// contains a value
+ RESULT_WARN_UNUSED
+ constexpr auto has_error() const noexcept -> bool;
+
+ //-------------------------------------------------------------------------
+
+ /// \{
+ /// \brief Returns a reference to the contained value
+ ///
+ /// This function provides checked (throwing) access to the underlying
+ /// value. The constness and refness of this result is propagated to the
+ /// underlying reference.
+ ///
+ /// If this contains an error, an exception is thrown containing the
+ /// underlying error. The error is consumed propagating the same constness
+ /// and refness of this result.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// assert(cpp::result<int,int>{42}.value() == 42);
+ ///
+ /// auto r = cpp::result<std::unique_ptr<int>,int>{
+ /// std::make_unique<int>(42)
+ /// };
+ /// auto s = std::move(r).value();
+ ///
+ /// try {
+ /// auto r = cpp::result<int,int>{ cpp::fail(42) };
+ /// auto v = r.value();
+ /// } catch (const cpp::bad_result_access<int>& e) {
+ /// assert(e.error() == 42);
+ /// }
+ /// ```
+ ///
+ /// \throws bad_result_access<E> if `*this` does not contain a value.
+ ///
+ /// \return the value of `*this`
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto value()
+ & -> typename std::add_lvalue_reference<T>::type;
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto value()
+ && -> typename std::add_rvalue_reference<T>::type;
+ RESULT_WARN_UNUSED
+ constexpr auto value()
+ const & -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type;
+ RESULT_WARN_UNUSED
+ constexpr auto value()
+ const && -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
+ /// \}
+
+ /// \{
+ /// \brief Returns the contained error, if one exists, or a
+ /// default-constructed error value
+ ///
+ /// The `error()` function will not throw any exceptions if `E` does not
+ /// throw any exceptions for the copy or move construction.
+ ///
+ /// This is to limit the possible scope for exceptions, and to allow the
+ /// error type to be treated as a "status"-like type, where the
+ /// default-constructed case is considered the "good" state.
+ ///
+ /// If this function is invoked on an rvalue of a result, the error is
+ /// returned via move-construction
+ ///
+ /// ### Requires
+ ///
+ /// * `std::is_default_constructible<E>::value` is `true`
+ /// * `std::is_copy_constructible<E>::value` or
+ /// `std::is_move_constructible<E>::value` is `true`
+ /// * `E{}` represents the "good" (non-error) state
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,std::error_code>{ 42 };
+ /// assert(r.error() == std::error_code{});
+ ///
+ /// auto r = cpp::result<int,std::error_code>{
+ /// cpp::fail(std::io_errc::stream)
+ /// };
+ ///
+ /// assert(r.error() == std::io_errc::stream);
+ /// ```
+ ///
+ /// \return the error or a default-constructed error value
+ RESULT_WARN_UNUSED
+ constexpr auto error() const &
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E;
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto error() &&
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_move_constructible<E>::value) -> E;
+ /// }
+
+ /// \{
+ /// \brief Asserts an expectation that this result contains an error,
+ /// throwing a bad_result_access on failure
+ ///
+ /// If this function is invoked from an rvalue of `result`, then this will
+ /// consume the underlying error first, if there is one.
+ ///
+ /// \note This function exists as a means to allow for results to be marked
+ /// `used` without requiring directly inspecting the underlying value.
+ /// This is, in effect, equivalent to `assert(res.has_value())`,
+ /// however it uses exceptions to ensure the stack can be unwound, and
+ /// exceptions invoked.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto start_service() -> cpp::result<void,int>;
+ ///
+ /// start_service().expect("Service failed to start!");
+ /// ```
+ ///
+ /// \param message the message to provide to this expectation
+ template <typename String,
+ typename = typename std::enable_if<(
+ std::is_convertible<String,const std::string&>::value &&
+ std::is_copy_constructible<E>::value
+ )>::type>
+ RESULT_CPP14_CONSTEXPR auto expect(String&& message) const & -> void;
+ template <typename String,
+ typename = typename std::enable_if<(
+ std::is_convertible<String,const std::string&>::value &&
+ std::is_move_constructible<E>::value
+ )>::type>
+ RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> void;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Monadic Functionalities
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \{
+ /// \brief Returns the contained value if `*this` has a value,
+ /// otherwise returns \p default_value.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.value_or(0) == 42);
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.value_or(0) == 0);
+ /// ```
+ ///
+ /// \param default_value the value to use in case `*this` contains an error
+ /// \return the contained value or \p default_value
+ template <typename U>
+ RESULT_WARN_UNUSED
+ constexpr auto value_or(U&& default_value)
+ const & -> typename std::remove_reference<T>::type;
+ template <typename U>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto value_or(U&& default_value)
+ && -> typename std::remove_reference<T>::type;
+ /// \}
+
+ /// \{
+ /// \brief Returns the contained error if `*this` has an error,
+ /// otherwise returns \p default_error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.error_or(0) == cpp::fail(0));
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.error_or(0) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param default_error the error to use in case `*this` is empty
+ /// \return the contained value or \p default_error
+ template <typename U>
+ RESULT_WARN_UNUSED
+ constexpr auto error_or(U&& default_error) const & -> error_type;
+ template <typename U>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type;
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Returns a result containing \p value if this result contains
+ /// a value, otherwise returns a result containing the current
+ /// error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.and_then(100) == 100);
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.and_then(100) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param value the value to return as a result
+ /// \return a result of \p value if this contains a value
+ template <typename U>
+ RESULT_WARN_UNUSED
+ constexpr auto and_then(U&& value) const -> result<typename std::decay<U>::type,E>;
+
+ /// \{
+ /// \brief Invokes the function \p fn with the value of this result as
+ /// the argument
+ ///
+ /// If this result contains an error, a result of the error is returned
+ ///
+ /// The function being called must return a `result` type or the program
+ /// is ill-formed
+ ///
+ /// If this is called on an rvalue of `result` which contains an error,
+ /// the returned `result` is constructed from an rvalue of that error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto to_string(int) -> cpp::result<std::string,int>;
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.flat_map(to_string) == "42");
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.flat_map(to_string) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result of the function being called
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto flat_map(Fn&& fn) const & -> detail::invoke_result_t<Fn, const T&>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn, T&&>;
+ /// \}
+
+ /// \{
+ /// \brief Invokes the function \p fn with the value of this result as
+ /// the argument
+ ///
+ /// If this result is an error, the result of this function is that
+ /// error. Otherwise this function wraps the result and returns it as an
+ /// result.
+ ///
+ /// If this is called on an rvalue of `result` which contains an error,
+ /// the returned `result` is constructed from an rvalue of that error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto to_string(int) -> std::string;
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.map(to_string) == "42");
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.map(to_string) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result result of the function invoked
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto map(Fn&& fn) const & -> result<detail::invoke_result_t<Fn,const T&>,E>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result<detail::invoke_result_t<Fn,T&&>,E>;
+ /// \}
+
+ /// \{
+ /// \brief Invokes the function \p fn with the error of this result as
+ /// the argument
+ ///
+ /// If this result contains a value, the result of this function is that
+ /// value. Otherwise the function is called with that error and returns the
+ /// result as a result.
+ ///
+ /// If this is called on an rvalue of `result` which contains a value,
+ /// the returned `result` is constructed from an rvalue of that value.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto to_string(int) -> std::string;
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.map_error(to_string) == 42);
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.map_error(to_string) == cpp::fail("42"));
+ ///
+ /// auto r = cpp::result<std::string,int>{};
+ /// auto s = r.map(std::string::size); // 's' contains 'result<size_t,int>'
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result result of the function invoked
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto map_error(Fn&& fn)
+ const & -> result<T, detail::invoke_result_t<Fn,const E&>>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto map_error(Fn&& fn)
+ && -> result<T, detail::invoke_result_t<Fn,E&&>>;
+ /// \}
+
+ /// \{
+ /// \brief Invokes the function \p fn with the error of this result as
+ /// the argument
+ ///
+ /// If this result contains a value, a result of the value is returned
+ ///
+ /// The function being called must return a `result` type or the program
+ /// is ill-formed
+ ///
+ /// If this is called on an rvalue of `result` which contains an error,
+ /// the returned `result` is constructed from an rvalue of that error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto to_string(int) -> cpp::result<int,std::string>;
+ /// auto r = cpp::result<int,int>{42};
+ /// assert(r.flat_map(to_string) == 42);
+ ///
+ /// auto r = cpp::result<int,int>{cpp::fail(42)};
+ /// assert(r.flat_map(to_string) == cpp::fail("42"));
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result of the function being called
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto flat_map_error(Fn&& fn)
+ const & -> detail::invoke_result_t<Fn, const E&>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn)
+ && -> detail::invoke_result_t<Fn, E&&>;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Private Members
+ //-------------------------------------------------------------------------
+ private:
+
+ detail::result_storage<T,E> m_storage;
+
+ //-------------------------------------------------------------------------
+ // Private Monadic Functions
+ //-------------------------------------------------------------------------
+ private:
+
+ /// \{
+ /// \brief Map implementations for void and non-void functions
+ ///
+ /// \param fn the function
+ template <typename Fn>
+ constexpr auto map_impl(std::true_type, Fn&& fn) const & -> result<void,E>;
+ template <typename Fn>
+ constexpr auto map_impl(std::false_type, Fn&& fn) const & -> result<detail::invoke_result_t<Fn,const T&>,E>;
+ template <typename Fn>
+ RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result<void,E>;
+ template <typename Fn>
+ RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn,T&&>,E>;
+ /// \}
+ };
+
+ //===========================================================================
+ // class : result<void,E>
+ //===========================================================================
+
+ /////////////////////////////////////////////////////////////////////////////
+ /// \brief Partial specialization of `result<void, E>`
+ ///
+ /// \tparam E the underlying error type
+ /////////////////////////////////////////////////////////////////////////////
+ template <typename E>
+ class RESULT_NODISCARD result<void,E>
+ {
+ // Type requirements
+
+ static_assert(
+ !std::is_void<typename std::decay<E>::type>::value,
+ "It is ill-formed for E to be (possibly CV-qualified) void type"
+ );
+ static_assert(
+ !std::is_abstract<E>::value,
+ "It is ill-formed for E to be abstract type"
+ );
+ static_assert(
+ !is_failure<typename std::decay<E>::type>::value,
+ "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type"
+ );
+ static_assert(
+ !std::is_reference<E>::value,
+ "It is ill-formed for E to be a reference type. "
+ "Only T types may be lvalue references"
+ );
+
+ // Friendship
+
+ friend detail::result_error_extractor;
+
+ template <typename T2, typename E2>
+ friend class result;
+
+ //-------------------------------------------------------------------------
+ // Public Member Types
+ //-------------------------------------------------------------------------
+ public:
+
+ using value_type = void; ///< The value type of this result
+ using error_type = E; ///< The error type of this result
+ using failure_type = failure<E>; ///< The failure type
+
+ template <typename U>
+ using rebind = result<U,E>; ///< Rebinds the result type
+
+ //-------------------------------------------------------------------------
+ // Constructor / Assignment
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \brief Constructs a `result` object in a value state
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<void,int>{};
+ /// ```
+ constexpr result() noexcept;
+
+ /// \brief Copy constructs this result
+ ///
+ /// If other contains an error, constructs an object that contains a copy
+ /// of that error.
+ ///
+ /// \note This constructor is defined as deleted if
+ /// `std::is_copy_constructible<E>::value` is `false`
+ ///
+ /// \note This constructor is defined as trivial if both
+ /// `std::is_trivially_copy_constructible<E>::value` are `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// const auto r = cpp::result<void,int>{};
+ /// const auto s = r;
+ /// ```
+ ///
+ /// \param other the result to copy
+ constexpr result(const result& other) = default;
+
+ /// \brief Move constructs a result
+ ///
+ /// If other contains an error, move-constructs this result from that
+ /// error.
+ ///
+ /// \note This constructor is defined as deleted if
+ /// `std::is_move_constructible<E>::value` is `false`
+ ///
+ /// \note This constructor is defined as trivial if both
+ /// `std::is_trivially_move_constructible<E>::value` are `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<void,std::string>{};
+ /// auto s = std::move(r);
+ /// ```
+ ///
+ /// \param other the result to move
+ constexpr result(result&& other) = default;
+
+ /// \brief Converting copy constructor
+ ///
+ /// If \p other contains a value, constructs a result object that is not
+ /// in an error state -- ignoring the value.
+ ///
+ /// If \p other contains an error, constructs a result object that
+ /// contains an error, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type `E`.
+ ///
+ /// \note This constructor does not participate in overload resolution
+ /// unless the following conditions are met:
+ /// - `std::is_constructible_v<E, const E2&>` is `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// const auto r = cpp::result<int,int>{42};
+ /// const auto s = cpp::result<void,int>{r};
+ /// ```
+ ///
+ /// \param other the other type to convert
+ template <typename U, typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
+ explicit result(const result<U,E2>& other)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value);
+
+ /// \brief Converting move constructor
+ ///
+ /// If \p other contains an error, constructs a result object that
+ /// contains an error, initialized as if direct-initializing
+ /// (but not direct-list-initializing) an object of type E&&.
+ ///
+ /// \note This constructor does not participate in overload resolution
+ /// unless the following conditions are met:
+ /// - `std::is_constructible_v<E, const E2&>` is `true`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<int,std::string>{42};
+ /// auto s = cpp::result<void,std::string>{
+ /// std::move(r)
+ /// };
+ /// ```
+ ///
+ /// \param other the other type to convert
+ template <typename U, typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
+ explicit result(result<U,E2>&& other)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value);
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Constructs a result object in a value state
+ ///
+ /// This constructor exists primarily for symmetry with the `result<T,E>`
+ /// constructor. Unlike the `T` overload, no variadic arguments may be
+ /// supplied.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<void,std::string>{cpp::in_place};
+ /// ```
+ constexpr explicit result(in_place_t) noexcept;
+
+ /// \brief Constructs a result object that contains an error
+ ///
+ /// the value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `E` from the arguments
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<void,std::string>{
+ /// cpp::in_place_error, "Hello world"
+ /// };
+ /// ```
+ ///
+ /// \param args the arguments to pass to `E`'s constructor
+ template <typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E,Args...>::value>::type>
+ constexpr explicit result(in_place_error_t, Args&&... args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value);
+
+ /// \brief Constructs a result object that contains an error
+ ///
+ /// The value is initialized as if direct-initializing (but not
+ /// direct-list-initializing) an object of type `E` from the arguments
+ /// `std::forward<std::initializer_list<U>>(ilist)`,
+ /// `std::forward<Args>(args)...`
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto r = cpp::result<void,std::string>{
+ /// cpp::in_place_error, {'H','e','l','l','o'}
+ /// };
+ /// ```
+ ///
+ /// \param ilist An initializer list of entries to forward
+ /// \param args the arguments to pass to Es constructor
+ template <typename U, typename...Args,
+ typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>&, Args...>::value>::type>
+ constexpr explicit result(in_place_error_t,
+ std::initializer_list<U> ilist,
+ Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value);
+
+ //-------------------------------------------------------------------------
+
+ /// \{
+ /// \brief Constructs the underlying error of this result
+ ///
+ /// \note This constructor only participates in overload resolution if
+ /// `E` is constructible from \p e
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// cpp::result<void,int> r = cpp::fail(42);
+ ///
+ /// auto get_error_result() -> cpp::result<void,std::string> {
+ /// return cpp::fail("hello world!");
+ /// }
+ /// ```
+ ///
+ /// \param e the failure error
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,const E2&>::value>::type>
+ constexpr /* implicit */ result(const failure<E2>& e)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value);
+ template <typename E2,
+ typename = typename std::enable_if<std::is_constructible<E,E2&&>::value>::type>
+ constexpr /* implicit */ result(failure<E2>&& e)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value);
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \brief Copy assigns the result stored in \p other
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_copy_constructible_v<E>` is `true`
+ /// this restriction guarantees that no 'valueless_by_exception` state
+ /// may occur.
+ ///
+ /// \note This assignment operator is defined as trivial if the following
+ /// conditions are all `true`:
+ /// - `std::is_trivially_copy_constructible<E>::value`
+ /// - `std::is_trivially_copy_assignable<E>::value`
+ /// - `std::is_trivially_destructible<E>::value`
+ ///
+ /// \param other the other result to copy
+ auto operator=(const result& other) -> result& = default;
+
+ /// \brief Move assigns the result stored in \p other
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_copy_constructible_v<E>` is `true`
+ /// this restriction guarantees that no 'valueless_by_exception` state
+ /// may occur.
+ ///
+ /// \note This assignment operator is defined as trivial if the following
+ /// conditions are all `true`:
+ /// - `std::is_trivially_move_constructible<E>::value`
+ /// - `std::is_trivially_move_assignable<E>::value`
+ /// - `std::is_trivially_destructible<E>::value`
+ ///
+ /// \param other the other result to copy
+ auto operator=(result&& other) -> result& = default;
+
+ /// \brief Copy-converts the state of \p other
+ ///
+ /// If both this and \p other contain an error, the underlying error is
+ /// assigned through copy-assignment.
+ ///
+ /// If \p other contains a value state, this result is constructed in a
+ /// value state.
+ ///
+ /// If \p other contans an error state, and this contains a value state,
+ /// the underlying error is constructed through copy-construction.
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<E, const E2&>`,
+ /// `std::is_assignable_v<E&, const E2&>` are all `true`.
+ ///
+ /// \param other the other result object to convert
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<std::is_nothrow_constructible<E,const E2&>::value &&
+ std::is_assignable<E&,const E2&>::value>::type>
+ auto operator=(const result<void,E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&;
+
+ /// \brief Move-converts the state of \p other
+ ///
+ /// If both this and \p other contain an error, the underlying error is
+ /// assigned through move-assignment.
+ ///
+ /// If \p other contains a value state, this result is constructed in a
+ /// value state.
+ ///
+ /// If \p other contans an error state, and this contains a value state,
+ /// the underlying error is constructed through move-construction.
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<E, E2&&>`,
+ /// `std::is_assignable_v<E&, E2&&>` are all `true`.
+ ///
+ /// \param other the other result object to convert
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<std::is_nothrow_constructible<E,E2&&>::value &&
+ std::is_assignable<E&,E2&&>::value>::type>
+ auto operator=(result<void,E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&;
+
+ /// \{
+ /// \brief Perfect-forwarded assignment
+ ///
+ /// Depending on whether `*this` contains an error before the call, the
+ /// contained error is either direct-initialized via forwarding the error,
+ /// or assigned from forwarding the error
+ ///
+ /// \note The function does not participate in overload resolution unless
+ /// - `std::is_nothrow_constructible_v<E, E2>` is `true`, and
+ /// - `std::is_assignable_v<E&, E2>` is `true`
+ ///
+ /// \param other the failure value to assign to this
+ /// \return reference to `(*this)`
+ template <typename E2,
+ typename = typename std::enable_if<detail::result_is_failure_assignable<E,const E2&>::value>::type>
+ auto operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&;
+ template <typename E2,
+ typename = typename std::enable_if<detail::result_is_failure_assignable<E,E2&&>::value>::type>
+ auto operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Observers
+ //-------------------------------------------------------------------------
+ public:
+
+
+ /// \brief Contextually convertible to `true` if `*this` does not contain
+ /// an error
+ ///
+ /// This function exists to allow for simple, terse checks for containing
+ /// a value.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto get_result() -> cpp::result<void, int>;
+ /// auto r = get_result();
+ /// if (r) { ... }
+ ///
+ /// assert(static_cast<bool>(cpp::result<void,int>{}));
+ ///
+ /// assert(!static_cast<bool>(cpp::result<void,int>{cpp::fail(42)}));
+ /// ```
+ ///
+ /// \return `true` if `*this` contains a value, `false` if `*this`
+ /// does not contain a value
+ RESULT_WARN_UNUSED
+ constexpr explicit operator bool() const noexcept;
+
+ /// \copydoc result<T,E>::has_value
+ RESULT_WARN_UNUSED
+ constexpr auto has_value() const noexcept -> bool;
+
+ /// \copydoc result<T,E>::has_error
+ RESULT_WARN_UNUSED
+ constexpr auto has_error() const noexcept -> bool;
+
+ //-------------------------------------------------------------------------
+
+ /// \{
+ /// \brief Throws an exception if `(*this)` is in an error state
+ ///
+ /// This function exists for symmetry with `cpp::result<T,E>` objects where
+ /// `T` contains a value.
+ ///
+ /// If this contains an error, an exception is thrown containing the
+ /// underlying error. The error is consumed propagating the same constness
+ /// and refness of this result.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// cpp::result<void,int>{}.value(); // no exception
+ ///
+ /// auto r = cpp::result<void,std::unique_ptr<int>>{
+ /// cpp::fail(std::make_unique<int>(42))
+ /// };
+ /// std::move(r).value(); // throws bad_result_access<std::unique_ptr<int>>
+ ///
+ /// try {
+ /// auto r = cpp::result<void,int>{ cpp::fail(42) }.value();
+ /// } catch (const cpp::bad_result_access<int>& e) {
+ /// assert(e.error() == 42);
+ /// }
+ /// ```
+ ///
+ /// \throws bad_result_access<E> if `*this` does not contain a value.
+ RESULT_CPP14_CONSTEXPR auto value() && -> void;
+ RESULT_CPP14_CONSTEXPR auto value() const & -> void;
+ /// \}
+
+ /// \{
+ /// \copydoc result<T,E>::error
+ RESULT_WARN_UNUSED
+ constexpr auto error() const &
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E;
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto error() &&
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E;
+ /// \}
+
+ /// \{
+ /// \copydoc result<T,E>::expect
+ template <typename String,
+ typename = typename std::enable_if<(
+ std::is_convertible<String,const std::string&>::value &&
+ std::is_copy_constructible<E>::value
+ )>::type>
+ RESULT_CPP14_CONSTEXPR auto expect(String&& message) const & -> void;
+ template <typename String,
+ typename = typename std::enable_if<(
+ std::is_convertible<String,const std::string&>::value &&
+ std::is_move_constructible<E>::value
+ )>::type>
+ RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> void;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Monadic Functionalities
+ //-------------------------------------------------------------------------
+ public:
+
+ /// \{
+ /// \copydoc result<T,E>::error_or
+ template <typename U>
+ RESULT_WARN_UNUSED
+ constexpr auto error_or(U&& default_error) const & -> error_type;
+ template <typename U>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type;
+ /// \}
+
+ //-------------------------------------------------------------------------
+
+ /// \copydoc result<T,E>::and_then
+ template <typename U>
+ RESULT_WARN_UNUSED
+ constexpr auto and_then(U&& value) const -> result<typename std::decay<U>::type,E>;
+
+ /// \{
+ /// \brief Invokes the function \p fn if `(*this)` contains no value
+ ///
+ /// If this result contains an error, a result of the error is returned
+ ///
+ /// The function being called must return a `result` type or the program
+ /// is ill-formed
+ ///
+ /// If this is called on an rvalue of `result` which contains an error,
+ /// the returned `result` is constructed from an rvalue of that error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto generate_int() -> cpp::result<int,int> { return 42; }
+ /// auto r = cpp::result<void,int>{};
+ /// assert(r.flat_map(generate_int) == 42);
+ ///
+ /// auto r = cpp::result<void,int>{cpp::fail(42)};
+ /// assert(r.flat_map(generate_int) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result of the function being called
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto flat_map(Fn&& fn) const & -> detail::invoke_result_t<Fn>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn>;
+ /// \}
+
+ /// \{
+ /// \brief Invokes the function \p fn if `(*this)` contains no value
+ ///
+ /// If this result is an error, the result of this function is that
+ /// error. Otherwise this function wraps the result and returns it as an
+ /// result.
+ ///
+ /// If this is called on an rvalue of `result` which contains an error,
+ /// the returned `result` is constructed from an rvalue of that error.
+ ///
+ /// ### Examples
+ ///
+ /// Basic Usage:
+ ///
+ /// ```cpp
+ /// auto generate_int() -> int { return 42; }
+ /// auto r = cpp::result<void,int>{};
+ /// assert(r.map(generate_int) == 42);
+ ///
+ /// auto r = cpp::result<void,int>{cpp::fail(42)};
+ /// assert(r.map(generate_int) == cpp::fail(42));
+ /// ```
+ ///
+ /// \param fn the function to invoke with this
+ /// \return The result result of the function invoked
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto map(Fn&& fn) const & -> result<detail::invoke_result_t<Fn>,E>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result<detail::invoke_result_t<Fn>,E>;
+ /// \}
+
+ /// \{
+ /// \copydoc result<T,E>::map_error
+ template <typename Fn>
+ constexpr auto map_error(Fn&& fn) const & -> result<void, detail::invoke_result_t<Fn,const E&>>;
+ template <typename Fn>
+ RESULT_CPP14_CONSTEXPR
+ auto map_error(Fn&& fn) && -> result<void, detail::invoke_result_t<Fn,E&&>>;
+ /// \}
+
+
+ /// \{
+ /// \copydoc result<T,E>::flat_map_error
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ constexpr auto flat_map_error(Fn&& fn) const & -> detail::invoke_result_t<Fn, const E&>;
+ template <typename Fn>
+ RESULT_WARN_UNUSED
+ RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn) && -> detail::invoke_result_t<Fn, E&&>;
+ /// \}
+
+ //-------------------------------------------------------------------------
+ // Private Members
+ //-------------------------------------------------------------------------
+ private:
+
+ detail::result_storage<detail::unit,E> m_storage;
+
+ //-------------------------------------------------------------------------
+ // Private Monadic Functions
+ //-------------------------------------------------------------------------
+ private:
+
+ /// \{
+ /// \brief Map implementations for void and non-void functions
+ ///
+ /// \param fn the function
+ template <typename Fn>
+ constexpr auto map_impl(std::true_type, Fn&& fn) const & -> result<void,E>;
+ template <typename Fn>
+ constexpr auto map_impl(std::false_type, Fn&& fn) const & -> result<detail::invoke_result_t<Fn>,E>;
+ template <typename Fn>
+ RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result<void,E>;
+ template <typename Fn>
+ RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn>,E>;
+ /// \}
+ };
+
+ //===========================================================================
+ // non-member functions : class : result
+ //===========================================================================
+
+ //---------------------------------------------------------------------------
+ // Comparison
+ //---------------------------------------------------------------------------
+
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator==(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator!=(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator>=(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator<=(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator>(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+ template <typename T1, typename E1, typename T2, typename E2>
+ constexpr auto operator<(const result<T1,E1>& lhs, const result<T2,E2>& rhs)
+ noexcept -> bool;
+
+ //---------------------------------------------------------------------------
+
+ template <typename E1, typename E2>
+ constexpr auto operator==(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator!=(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator>=(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator<=(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator>(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+ template <typename E1, typename E2>
+ constexpr auto operator<(const result<void,E1>& lhs, const result<void,E2>& rhs)
+ noexcept -> bool;
+
+ //---------------------------------------------------------------------------
+
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator==(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator==(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator!=(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator!=(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator<=(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator<=(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator>=(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator>=(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator<(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator<(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U,
+ typename = typename std::enable_if<!std::is_same<T,void>::value>::type>
+ constexpr auto operator>(const result<T,E>& exp, const U& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E,
+ typename = typename std::enable_if<!std::is_same<U,void>::value>::type>
+ constexpr auto operator>(const T& value, const result<U,E>& exp)
+ noexcept -> bool;
+
+ //---------------------------------------------------------------------------
+
+ template <typename T, typename E, typename U>
+ constexpr auto operator==(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator==(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U>
+ constexpr auto operator!=(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator!=(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U>
+ constexpr auto operator<=(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator<=(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U>
+ constexpr auto operator>=(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator>=(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U>
+ constexpr auto operator<(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator<(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+ template <typename T, typename E, typename U>
+ constexpr auto operator>(const result<T,E>& exp, const failure<U>& value)
+ noexcept -> bool;
+ template <typename T, typename U, typename E>
+ constexpr auto operator>(const failure<T>& value, const result<E,U>& exp)
+ noexcept -> bool;
+
+ //---------------------------------------------------------------------------
+ // Utilities
+ //---------------------------------------------------------------------------
+
+ /// \{
+ /// \brief Swaps the contents of \p lhs with \p rhs
+ ///
+ /// \param lhs the left result
+ /// \param rhs the right result
+ template <typename T, typename E>
+ auto swap(result<T,E>& lhs, result<T,E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_move_constructible<result<T,E>>::value &&
+ std::is_nothrow_move_assignable<result<T,E>>::value &&
+ std::is_nothrow_swappable<T>::value &&
+ std::is_nothrow_swappable<E>::value)
+#else
+ noexcept(std::is_nothrow_move_constructible<result<T,E>>::value &&
+ std::is_nothrow_move_assignable<result<T,E>>::value)
+#endif
+ -> void;
+ template <typename E>
+ auto swap(result<void,E>& lhs, result<void,E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_move_constructible<result<void,E>>::value &&
+ std::is_nothrow_move_assignable<result<void,E>>::value &&
+ std::is_nothrow_swappable<E>::value)
+#else
+ noexcept(std::is_nothrow_move_constructible<result<void,E>>::value &&
+ std::is_nothrow_move_assignable<result<void,E>>::value)
+#endif
+ -> void;
+ /// \}
+
+} // inline namespace bitwizeshift
+} // namespace EXPECTED_NAMESPACE
+
+namespace std {
+
+ template <typename T, typename E>
+ struct hash<::RESULT_NS_IMPL::result<T,E>>
+ {
+ auto operator()(const RESULT_NS_IMPL::result<T,E>& x) const -> std::size_t
+ {
+ if (x.has_value()) {
+ return std::hash<T>{}(*x) + 1; // add '1' to differentiate from error case
+ }
+ return std::hash<E>{}(::RESULT_NS_IMPL::detail::extract_error(x));
+ }
+ };
+
+ template <typename E>
+ struct hash<::RESULT_NS_IMPL::result<void,E>>
+ {
+ auto operator()(const RESULT_NS_IMPL::result<void,E>& x) const -> std::size_t
+ {
+ if (x.has_value()) {
+ return 0;
+ }
+ return std::hash<E>{}(::RESULT_NS_IMPL::detail::extract_error(x));
+ }
+ };
+
+} // namespace std
+
+#if !defined(RESULT_DISABLE_EXCEPTIONS)
+
+//=============================================================================
+// class : bad_result_access
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructors
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(E2&& error)
+ : logic_error{"error attempting to access value from result containing error"},
+ m_error(detail::forward<E2>(error))
+{
+
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(
+ const char* what_arg,
+ E2&& error
+) : logic_error{what_arg},
+ m_error(detail::forward<E2>(error))
+{
+
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(
+ const std::string& what_arg,
+ E2&& error
+) : logic_error{what_arg},
+ m_error(detail::forward<E2>(error))
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Observers
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::bad_result_access<E>::error()
+ & noexcept -> E&
+{
+ return m_error;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::bad_result_access<E>::error()
+ && noexcept -> E&&
+{
+ return static_cast<E&&>(m_error);
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::bad_result_access<E>::error()
+ const & noexcept -> const E&
+{
+ return m_error;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::bad_result_access<E>::error()
+ const && noexcept -> const E&&
+{
+ return static_cast<const E&&>(m_error);
+}
+
+#endif
+
+//=============================================================================
+// class : failure
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructors
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : m_failure(detail::forward<Args>(args)...)
+{
+
+}
+
+template <typename E>
+template <typename U, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(
+ in_place_t,
+ std::initializer_list<U> ilist,
+ Args&&...args
+) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value)
+ : m_failure(ilist, detail::forward<Args>(args)...)
+{
+
+}
+
+template <typename E>
+template <typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::failure_is_explicit_value_convertible<E,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(E2&& error)
+ noexcept(std::is_nothrow_constructible<E,E2>::value)
+ : m_failure(detail::forward<E2>(error))
+{
+
+}
+
+template <typename E>
+template <typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::failure_is_implicit_value_convertible<E,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(E2&& error)
+ noexcept(std::is_nothrow_constructible<E,E2>::value)
+ : m_failure(detail::forward<E2>(error))
+{
+
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(const failure<E2>& other)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value)
+ : m_failure(other.error())
+{
+
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::failure<E>::failure(failure<E2>&& other)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value)
+ : m_failure(static_cast<failure<E2>&&>(other).error())
+{
+
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::failure<E>::operator=(E2&& error)
+ noexcept(
+ std::is_nothrow_assignable<E,E2>::value ||
+ std::is_lvalue_reference<E>::value
+ ) -> failure&
+{
+ m_failure = detail::forward<E2>(error);
+
+ return (*this);
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::failure<E>::operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E,const E2&>::value)
+ -> failure&
+{
+ m_failure = other.error();
+
+ return (*this);
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::failure<E>::operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E,E2&&>::value)
+ -> failure&
+{
+ m_failure = static_cast<failure<E2>&&>(other).error();
+
+ return (*this);
+}
+
+//-----------------------------------------------------------------------------
+// Observers
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::failure<E>::error()
+ & noexcept -> typename std::add_lvalue_reference<E>::type
+{
+ return m_failure;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::failure<E>::error()
+ && noexcept -> typename std::add_rvalue_reference<E>::type
+{
+ using reference = typename std::add_rvalue_reference<E>::type;
+
+ return static_cast<reference>(m_failure);
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::failure<E>::error()
+ const & noexcept
+ -> typename std::add_lvalue_reference<typename std::add_const<E>::type>::type
+{
+ return m_failure;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::failure<E>::error()
+ const && noexcept
+ -> typename std::add_rvalue_reference<typename std::add_const<E>::type>::type
+{
+ using reference = typename std::add_rvalue_reference<typename std::add_const<E>::type>::type;
+
+ return static_cast<reference>(m_failure);
+}
+
+//=============================================================================
+// non-member functions : class : failure
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Comparison
+//-----------------------------------------------------------------------------
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() == rhs.error();
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() != rhs.error();
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() < rhs.error();
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() > rhs.error();
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() <= rhs.error();
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const failure<E1>& lhs, const failure<E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.error() >= rhs.error();
+}
+
+//-----------------------------------------------------------------------------
+// Utilities
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::fail(E&& e)
+ noexcept(std::is_nothrow_constructible<typename std::decay<E>::type,E>::value)
+ -> failure<typename std::decay<E>::type>
+{
+ using result_type = failure<typename std::decay<E>::type>;
+
+ return result_type(
+ detail::forward<E>(e)
+ );
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::fail(std::reference_wrapper<E> e)
+ noexcept -> failure<E&>
+{
+ using result_type = failure<E&>;
+
+ return result_type{e.get()};
+}
+
+template <typename E, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::fail(Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ -> failure<E>
+{
+ return failure<E>(in_place, detail::forward<Args>(args)...);
+}
+
+template <typename E, typename U, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::fail(std::initializer_list<U> ilist, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value)
+ -> failure<E>
+{
+ return failure<E>(in_place, ilist, detail::forward<Args>(args)...);
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::swap(failure<E>& lhs, failure<E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_swappable<E>::value) -> void
+#else
+ noexcept(std::is_nothrow_move_constructible<E>::value)
+ -> void
+#endif
+{
+ using std::swap;
+
+ swap(lhs.error(), rhs.error());
+}
+
+//=============================================================================
+// class : detail::result_union<T, E, IsTrivial>
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructors / Assignment
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E, bool IsTrivial>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>
+ ::result_union(unit)
+ noexcept
+ : m_empty{}
+{
+ // m_has_value intentionally not set
+}
+
+template <typename T, typename E, bool IsTrivial>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::detail::result_union<T,E,IsTrivial>
+ ::result_union(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value)
+ : m_value(detail::forward<Args>(args)...),
+ m_has_value{true}
+{
+}
+
+template <typename T, typename E, bool IsTrivial>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::detail::result_union<T,E,IsTrivial>
+ ::result_union(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : m_error(detail::forward<Args>(args)...),
+ m_has_value{false}
+{
+}
+
+//-----------------------------------------------------------------------------
+// Modifiers
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E, bool IsTrivial>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>::destroy()
+ const noexcept -> void
+{
+ // do nothing
+}
+
+//=============================================================================
+// class : detail::result_union<T, E, false>
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructors / Destructor / Assignment
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_union<T, E, false>
+ ::result_union(unit)
+ noexcept
+ : m_empty{}
+{
+ // m_has_value intentionally not set
+}
+
+template <typename T, typename E>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::detail::result_union<T,E,false>
+ ::result_union(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value)
+ : m_value(detail::forward<Args>(args)...),
+ m_has_value{true}
+{
+}
+
+template <typename T, typename E>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::detail::result_union<T,E,false>
+ ::result_union(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : m_error(detail::forward<Args>(args)...),
+ m_has_value{false}
+{
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_union<T,E,false>
+ ::~result_union()
+ noexcept(std::is_nothrow_destructible<T>::value && std::is_nothrow_destructible<E>::value)
+{
+ destroy();
+}
+
+//-----------------------------------------------------------------------------
+// Modifiers
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_union<T, E, false>::destroy()
+ -> void
+{
+ if (m_has_value) {
+ m_value.~underlying_value_type();
+ } else {
+ m_error.~underlying_error_type();
+ }
+}
+
+//=============================================================================
+// class : result_construct_base<T, E>
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructors / Assignment
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_construct_base<T,E>::result_construct_base(unit)
+ noexcept
+ : storage{unit{}}
+{
+}
+
+template <typename T, typename E>
+template <typename...Args>
+inline constexpr RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_construct_base<T,E>::result_construct_base(
+ in_place_t,
+ Args&&...args
+) noexcept(std::is_nothrow_constructible<T, Args...>::value)
+ : storage{in_place, detail::forward<Args>(args)...}
+{
+}
+
+template <typename T, typename E>
+template <typename...Args>
+inline constexpr RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_construct_base<T,E>::result_construct_base(
+ in_place_error_t,
+ Args&&...args
+) noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : storage(in_place_error, detail::forward<Args>(args)...)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Construction / Assignment
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_value(Args&&...args)
+ noexcept(std::is_nothrow_constructible<T,Args...>::value)
+ -> void
+{
+ using value_type = typename storage_type::underlying_value_type;
+
+ auto* p = static_cast<void*>(std::addressof(storage.m_value));
+ new (p) value_type(detail::forward<Args>(args)...);
+ storage.m_has_value = true;
+}
+
+template <typename T, typename E>
+template <typename...Args>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_error(Args&&...args)
+ noexcept(std::is_nothrow_constructible<E,Args...>::value)
+ -> void
+{
+ using error_type = typename storage_type::underlying_error_type;
+
+ auto* p = static_cast<void*>(std::addressof(storage.m_error));
+ new (p) error_type(detail::forward<Args>(args)...);
+ storage.m_has_value = false;
+}
+
+template <typename T, typename E>
+template <typename Result>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_error_from_result(
+ Result&& other
+) -> void
+{
+ if (other.storage.m_has_value) {
+ construct_value();
+ } else {
+ construct_error(detail::forward<Result>(other).storage.m_error);
+ }
+}
+
+
+template <typename T, typename E>
+template <typename Result>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_from_result(
+ Result&& other
+) -> void
+{
+ if (other.storage.m_has_value) {
+ construct_value_from_result_impl(
+ std::is_lvalue_reference<T>{},
+ detail::forward<Result>(other).storage.m_value
+ );
+ } else {
+ construct_error(detail::forward<Result>(other).storage.m_error);
+ }
+}
+
+template <typename T, typename E>
+template <typename Value>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::assign_value(Value&& value)
+ noexcept(std::is_nothrow_assignable<T,Value>::value)
+ -> void
+{
+ if (!storage.m_has_value) {
+ storage.destroy();
+ construct_value(detail::forward<Value>(value));
+ } else {
+ storage.m_value = detail::forward<Value>(value);
+ }
+}
+
+template <typename T, typename E>
+template <typename Error>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::assign_error(Error&& error)
+ noexcept(std::is_nothrow_assignable<E,Error>::value)
+ -> void
+{
+ if (storage.m_has_value) {
+ storage.destroy();
+ construct_error(detail::forward<Error>(error));
+ } else {
+ storage.m_error = detail::forward<Error>(error);
+ }
+}
+
+template <typename T, typename E>
+template <typename Result>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::assign_from_result(Result&& other)
+ -> void
+{
+ if (other.storage.m_has_value != storage.m_has_value) {
+ storage.destroy();
+ construct_from_result(detail::forward<Result>(other));
+ } else if (storage.m_has_value) {
+ assign_value_from_result_impl(
+ std::is_lvalue_reference<T>{},
+ detail::forward<Result>(other)
+ );
+ } else {
+ storage.m_error = detail::forward<Result>(other).storage.m_error;
+ }
+}
+
+template <typename T, typename E>
+template <typename ReferenceWrapper>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_value_from_result_impl(
+ std::true_type,
+ ReferenceWrapper&& reference
+) noexcept -> void
+{
+ using value_type = typename storage_type::underlying_value_type;
+
+ auto* p = static_cast<void*>(std::addressof(storage.m_value));
+ new (p) value_type(reference.get());
+ storage.m_has_value = true;
+}
+
+template <typename T, typename E>
+template <typename Value>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::construct_value_from_result_impl(
+ std::false_type,
+ Value&& value
+) noexcept(std::is_nothrow_constructible<T,Value>::value) -> void
+{
+ using value_type = typename storage_type::underlying_value_type;
+
+ auto* p = static_cast<void*>(std::addressof(storage.m_value));
+ new (p) value_type(detail::forward<Value>(value));
+ storage.m_has_value = true;
+}
+
+template <typename T, typename E>
+template <typename Result>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::assign_value_from_result_impl(
+ std::true_type,
+ Result&& other
+) -> void
+{
+ // T is a reference; unwrap it
+ storage.m_value = other.storage.m_value.get();
+}
+
+template <typename T, typename E>
+template <typename Result>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_construct_base<T,E>::assign_value_from_result_impl(
+ std::false_type,
+ Result&& other
+) -> void
+{
+ storage.m_value = detail::forward<Result>(other).storage.m_value;
+}
+
+
+//=============================================================================
+// class : result_trivial_copy_ctor_base_impl
+//=============================================================================
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_trivial_copy_ctor_base_impl<T,E>
+ ::result_trivial_copy_ctor_base_impl(const result_trivial_copy_ctor_base_impl& other)
+ noexcept(std::is_nothrow_copy_constructible<T>::value &&
+ std::is_nothrow_copy_constructible<E>::value)
+ : base_type(unit{})
+{
+ using ctor_base = result_construct_base<T,E>;
+
+ ctor_base::construct_from_result(static_cast<const ctor_base&>(other));
+}
+
+//=============================================================================
+// class : result_trivial_move_ctor_base
+//=============================================================================
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::detail::result_trivial_move_ctor_base_impl<T, E>
+ ::result_trivial_move_ctor_base_impl(result_trivial_move_ctor_base_impl&& other)
+ noexcept(std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_constructible<E>::value)
+ : base_type(unit{})
+{
+ using ctor_base = result_construct_base<T,E>;
+
+ ctor_base::construct_from_result(static_cast<ctor_base&&>(other));
+}
+
+//=============================================================================
+// class : result_copy_assign_base
+//=============================================================================
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_trivial_copy_assign_base_impl<T, E>
+ ::operator=(const result_trivial_copy_assign_base_impl& other)
+ noexcept(std::is_nothrow_copy_constructible<T>::value &&
+ std::is_nothrow_copy_constructible<E>::value &&
+ std::is_nothrow_copy_assignable<T>::value &&
+ std::is_nothrow_copy_assignable<E>::value)
+ -> result_trivial_copy_assign_base_impl&
+{
+ using ctor_base = result_construct_base<T,E>;
+
+ ctor_base::assign_from_result(static_cast<const ctor_base&>(other));
+ return (*this);
+}
+
+//=========================================================================
+// class : result_move_assign_base
+//=========================================================================
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::result_trivial_move_assign_base_impl<T, E>
+ ::operator=(result_trivial_move_assign_base_impl&& other)
+ noexcept(std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_constructible<E>::value &&
+ std::is_nothrow_move_assignable<T>::value &&
+ std::is_nothrow_move_assignable<E>::value)
+ -> result_trivial_move_assign_base_impl&
+{
+ using ctor_base = result_construct_base<T,E>;
+
+ ctor_base::assign_from_result(static_cast<ctor_base&&>(other));
+ return (*this);
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::detail::result_error_extractor::get(const result<T,E>& exp)
+ noexcept -> const E&
+{
+ return exp.m_storage.storage.m_error;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::detail::result_error_extractor::get(result<T,E>& exp)
+ noexcept -> E&
+{
+ return exp.m_storage.storage.m_error;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::detail::extract_error(const result<T,E>& exp) noexcept -> const E&
+{
+ return result_error_extractor::get(exp);
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::throw_bad_result_access(E&& error) -> void
+{
+#if defined(RESULT_DISABLE_EXCEPTIONS)
+ std::fprintf(
+ stderr,
+ "error attempting to access value from result containing error\n"
+ );
+ std::abort();
+#else
+ using exception_type = bad_result_access<
+ typename std::remove_const<
+ typename std::remove_reference<E>::type
+ >::type
+ >;
+
+ throw exception_type{
+ detail::forward<E>(error)
+ };
+#endif
+}
+
+template <typename String, typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::detail::throw_bad_result_access_message(
+ String&& message,
+ E&& error
+) -> void
+{
+#if defined(RESULT_DISABLE_EXCEPTIONS)
+ const auto message_string = std::string{
+ detail::forward<String>(message)
+ };
+ std::fprintf(stderr, "%s\n", message_string.c_str());
+ std::abort();
+#else
+ using exception_type = bad_result_access<
+ typename std::remove_const<
+ typename std::remove_reference<E>::type
+ >::type
+ >;
+
+ throw exception_type{
+ detail::forward<String>(message),
+ detail::forward<E>(error)
+ };
+#endif
+}
+
+//=============================================================================
+// class : result<T,E>
+//=============================================================================
+
+template <typename T, typename E>
+template <typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result()
+ noexcept(std::is_nothrow_constructible<U>::value)
+ : m_storage(in_place)
+{
+
+}
+
+template <typename T, typename E>
+template <typename T2, typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_copy_convertible<T,E,T2,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<T, E>::result(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_constructible<T,const T2&>::value &&
+ std::is_nothrow_constructible<E,const E2&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_from_result(
+ static_cast<const result<T2,E2>&>(other).m_storage
+ );
+}
+
+template <typename T, typename E>
+template <typename T2, typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_copy_convertible<T,E,T2,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<T, E>::result(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_constructible<T,const T2&>::value &&
+ std::is_nothrow_constructible<E,const E2&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_from_result(
+ static_cast<const result<T2,E2>&>(other).m_storage
+ );
+}
+
+template <typename T, typename E>
+template <typename T2, typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_move_convertible<T,E,T2,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<T, E>::result(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_constructible<T,T2&&>::value &&
+ std::is_nothrow_constructible<E,E2&&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_from_result(
+ static_cast<result<T2,E2>&&>(other).m_storage
+ );
+}
+
+template <typename T, typename E>
+template <typename T2, typename E2,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_move_convertible<T,E,T2,E2>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<T, E>::result(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_constructible<T,T2&&>::value &&
+ std::is_nothrow_constructible<E,E2&&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_from_result(
+ static_cast<result<T2,E2>&&>(other).m_storage
+ );
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(in_place_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<T, Args...>::value)
+ : m_storage(in_place, detail::forward<Args>(args)...)
+{
+
+}
+
+template <typename T, typename E>
+template <typename U, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(
+ in_place_t,
+ std::initializer_list<U> ilist,
+ Args&&...args
+) noexcept(std::is_nothrow_constructible<T, std::initializer_list<U>, Args...>::value)
+ : m_storage(in_place, ilist, detail::forward<Args>(args)...)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : m_storage(in_place_error, detail::forward<Args>(args)...)
+{
+
+}
+
+template <typename T, typename E>
+template <typename U, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(
+ in_place_error_t,
+ std::initializer_list<U> ilist,
+ Args&&...args
+) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value)
+ : m_storage(in_place_error, ilist, detail::forward<Args>(args)...)
+{
+
+}
+
+//-------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(const failure<E2>& e)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value)
+ : m_storage(in_place_error, e.error())
+{
+
+}
+
+template <typename T, typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(failure<E2>&& e)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value)
+ : m_storage(in_place_error, static_cast<E2&&>(e.error()))
+{
+
+}
+
+template <typename T, typename E>
+template <typename U,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_value_convertible<T,U>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(U&& value)
+ noexcept(std::is_nothrow_constructible<T,U>::value)
+ : m_storage(in_place, detail::forward<U>(value))
+{
+
+}
+
+template <typename T, typename E>
+template <typename U,
+ typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_value_convertible<T,U>::value,int>::type>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T, E>::result(U&& value)
+ noexcept(std::is_nothrow_constructible<T,U>::value)
+ : m_storage(in_place, detail::forward<U>(value))
+{
+
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename T2, typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<T, E>::operator=(const result<T2,E2>& other)
+ noexcept(std::is_nothrow_assignable<T, const T2&>::value &&
+ std::is_nothrow_assignable<E, const E2&>::value)
+ -> result&
+{
+ m_storage.assign_from_result(
+ static_cast<const result<T2,E2>&>(other).m_storage
+ );
+ return (*this);
+}
+
+template <typename T, typename E>
+template <typename T2, typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<T, E>::operator=(result<T2,E2>&& other)
+ noexcept(std::is_nothrow_assignable<T, T2&&>::value &&
+ std::is_nothrow_assignable<E, E2&&>::value)
+ -> result&
+{
+ m_storage.assign_from_result(
+ static_cast<result<T2,E2>&&>(other).m_storage
+ );
+ return (*this);
+}
+
+template <typename T, typename E>
+template <typename U, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<T, E>::operator=(U&& value)
+ noexcept(std::is_nothrow_assignable<T, U>::value)
+ -> result&
+{
+ m_storage.assign_value(detail::forward<U>(value));
+ return (*this);
+}
+
+template <typename T, typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<T, E>::operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value)
+ -> result&
+{
+ m_storage.assign_error(other.error());
+ return (*this);
+}
+
+template <typename T, typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<T, E>::operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value)
+ -> result&
+{
+ m_storage.assign_error(static_cast<E2&&>(other.error()));
+ return (*this);
+}
+
+//-----------------------------------------------------------------------------
+// Observers
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::operator->()
+ noexcept -> typename std::remove_reference<T>::type*
+{
+ // Prior to C++17, std::addressof was not `constexpr`.
+ // Since `addressof` fixes a relatively obscure issue where users define a
+ // custom `operator&`, the pre-C++17 implementation has been defined to be
+ // `&(**this)` so that it may exist in constexpr contexts.
+#if __cplusplus >= 201703L
+ return std::addressof(**this);
+#else
+ return &(**this);
+#endif
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::operator->()
+ const noexcept -> typename std::remove_reference<typename std::add_const<T>::type>::type*
+{
+#if __cplusplus >= 201703L
+ return std::addressof(**this);
+#else
+ return &(**this);
+#endif
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::operator*()
+ & noexcept -> typename std::add_lvalue_reference<T>::type
+{
+ return m_storage.storage.m_value;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::operator*()
+ && noexcept -> typename std::add_rvalue_reference<T>::type
+{
+ using reference = typename std::add_rvalue_reference<T>::type;
+
+ return static_cast<reference>(m_storage.storage.m_value);
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::operator*()
+ const& noexcept -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type
+{
+ return m_storage.storage.m_value;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::operator*()
+ const&& noexcept -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type
+{
+ using reference = typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
+
+ return static_cast<reference>(m_storage.storage.m_value);
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<T,E>::operator bool()
+ const noexcept
+{
+ return m_storage.storage.m_has_value;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T,E>::has_value()
+ const noexcept -> bool
+{
+ return m_storage.storage.m_has_value;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T,E>::has_error()
+ const noexcept -> bool
+{
+ return !m_storage.storage.m_has_value;
+}
+
+//-----------------------------------------------------------------------------
+
+// The `has_value()` expression below is incorrectly identified as an unused
+// value, which results in the `-Wunused-value` warning. This is suppressed
+// to prevent false-positives
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunused-value"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-value"
+#elif defined(_MSC_VER)
+// Older MSVC versions incorrectly warn on returning a reference to a temporary.
+// This has been suppressed
+# pragma warning(push)
+# pragma warning(disable:4172)
+#endif
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::value()
+ & -> typename std::add_lvalue_reference<T>::type
+{
+ return (has_value() ||
+ (detail::throw_bad_result_access(m_storage.storage.m_error), false),
+ m_storage.storage.m_value
+ );
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::value()
+ && -> typename std::add_rvalue_reference<T>::type
+{
+ using reference = typename std::add_rvalue_reference<T>::type;
+
+ return (has_value() ||
+ (detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true),
+ static_cast<reference>(m_storage.storage.m_value)
+ );
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T,E>::value()
+ const & -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type
+{
+ return (has_value() ||
+ (detail::throw_bad_result_access(m_storage.storage.m_error), true),
+ m_storage.storage.m_value
+ );
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T,E>::value()
+ const && -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type
+{
+ using reference = typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
+
+ return (has_value() ||
+ (detail::throw_bad_result_access(static_cast<const E&&>(m_storage.storage.m_error)), true),
+ (static_cast<reference>(m_storage.storage.m_value))
+ );
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__)
+# pragma GCC diagnostic pop
+#elif defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T,E>::error() const &
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E
+{
+ static_assert(
+ std::is_default_constructible<E>::value,
+ "E must be default-constructible if 'error()' checks are used. "
+ "This is to allow for default-constructed error states to represent the "
+ "'good' state"
+ );
+
+ return m_storage.storage.m_has_value
+ ? E{}
+ : m_storage.storage.m_error;
+}
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::error() &&
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_move_constructible<E>::value) -> E
+{
+ static_assert(
+ std::is_default_constructible<E>::value,
+ "E must be default-constructible if 'error()' checks are used. "
+ "This is to allow for default-constructed error states to represent the "
+ "'good' state"
+ );
+
+ return m_storage.storage.m_has_value
+ ? E{}
+ : static_cast<E&&>(m_storage.storage.m_error);
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::expect(String&& message)
+ const & -> void
+{
+ if (has_error()) {
+ detail::throw_bad_result_access_message(
+ detail::forward<String>(message),
+ m_storage.storage.m_error
+ );
+ }
+}
+
+template <typename T, typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::expect(String&& message)
+ && -> void
+{
+ if (has_error()) {
+ detail::throw_bad_result_access_message(
+ detail::forward<String>(message),
+ static_cast<E&&>(m_storage.storage.m_error)
+ );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Monadic Functionalities
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::value_or(U&& default_value)
+ const& -> typename std::remove_reference<T>::type
+{
+ return m_storage.storage.m_has_value
+ ? m_storage.storage.m_value
+ : detail::forward<U>(default_value);
+}
+
+template <typename T, typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::value_or(U&& default_value)
+ && -> typename std::remove_reference<T>::type
+{
+ return m_storage.storage.m_has_value
+ ? static_cast<T&&>(**this)
+ : detail::forward<U>(default_value);
+}
+
+template <typename T, typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::error_or(U&& default_error)
+ const& -> error_type
+{
+ return m_storage.storage.m_has_value
+ ? detail::forward<U>(default_error)
+ : m_storage.storage.m_error;
+}
+
+template <typename T, typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::error_or(U&& default_error)
+ && -> error_type
+{
+ return m_storage.storage.m_has_value
+ ? detail::forward<U>(default_error)
+ : static_cast<E&&>(m_storage.storage.m_error);
+}
+
+template <typename T, typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::and_then(U&& value)
+ const -> result<typename std::decay<U>::type,E>
+{
+ return map([&value](const T&){
+ return detail::forward<U>(value);
+ });
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::flat_map(Fn&& fn)
+ const & -> detail::invoke_result_t<Fn, const T&>
+{
+ using result_type = detail::invoke_result_t<Fn, const T&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_value)
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::flat_map(Fn&& fn)
+ && -> detail::invoke_result_t<Fn, T&&>
+{
+ using result_type = detail::invoke_result_t<Fn, T&&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? detail::invoke(detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value))
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::map(Fn&& fn)
+ const & -> result<detail::invoke_result_t<Fn,const T&>,E>
+{
+ using result_type = detail::invoke_result_t<Fn,const T&>;
+
+ return map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn));
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::map(Fn&& fn)
+ && -> result<detail::invoke_result_t<Fn,T&&>,E>
+{
+ using result_type = detail::invoke_result_t<Fn,T&&>;
+
+ return static_cast<result<T,E>&&>(*this).map_impl(
+ std::is_void<result_type>{},
+ detail::forward<Fn>(fn)
+ );
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::map_error(Fn&& fn)
+ const & -> result<T, detail::invoke_result_t<Fn,const E&>>
+{
+ using result_type = result<T, detail::invoke_result_t<Fn, const E&>>;
+
+ return has_error()
+ ? result_type(in_place_error, detail::invoke(
+ detail::forward<Fn>(fn), m_storage.storage.m_error
+ ))
+ : result_type(in_place, m_storage.storage.m_value);
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::map_error(Fn&& fn)
+ && -> result<T, detail::invoke_result_t<Fn,E&&>>
+{
+ using result_type = result<T, detail::invoke_result_t<Fn, E&&>>;
+
+ return has_error()
+ ? result_type(in_place_error, detail::invoke(
+ detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error)
+ ))
+ : result_type(static_cast<T&&>(m_storage.storage.m_value));
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::flat_map_error(Fn&& fn)
+ const & -> detail::invoke_result_t<Fn, const E&>
+{
+ using result_type = detail::invoke_result_t<Fn, const E&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map_error must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? result_type(in_place, m_storage.storage.m_value)
+ : detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error);
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::flat_map_error(Fn&& fn)
+ && -> detail::invoke_result_t<Fn, E&&>
+{
+ using result_type = detail::invoke_result_t<Fn, E&&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map_error must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? result_type(in_place, static_cast<T&&>(m_storage.storage.m_value))
+ : detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error));
+}
+
+//-----------------------------------------------------------------------------
+// Private Monadic Functions
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::map_impl(std::true_type, Fn&& fn)
+ const & -> result<void,E>
+{
+ using result_type = result<void, E>;
+
+ return has_value()
+ ? (detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_value), result_type{})
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<T, E>::map_impl(std::false_type, Fn&& fn)
+ const & -> result<detail::invoke_result_t<Fn,const T&>,E>
+{
+ using invoke_result_type = detail::invoke_result_t<Fn,const T&>;
+ using result_type = result<invoke_result_type, E>;
+
+ return has_value()
+ ? result_type(in_place, detail::invoke(
+ detail::forward<Fn>(fn), m_storage.storage.m_value
+ ))
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::map_impl(std::true_type, Fn&& fn)
+ && -> result<void,E>
+{
+ using result_type = result<void, E>;
+
+ return has_value()
+ ? (detail::invoke(
+ detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value)
+ ), result_type{})
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+template <typename T, typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T, E>::map_impl(std::false_type, Fn&& fn)
+ && -> result<detail::invoke_result_t<Fn,T&&>,E>
+{
+ using invoke_result_type = detail::invoke_result_t<Fn,T&&>;
+ using result_type = result<invoke_result_type, E>;
+
+ return has_value()
+ ? result_type(in_place, detail::invoke(
+ detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value)
+ ))
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+//=============================================================================
+// class : result<void,E>
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Constructor / Assignment
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result()
+ noexcept
+ : m_storage(in_place)
+{
+
+}
+
+template <typename E>
+template <typename U, typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<void, E>::result(const result<U,E2>& other)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_error_from_result(
+ static_cast<const result<U,E2>&>(other).m_storage
+ );
+}
+
+template <typename E>
+template <typename U, typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+RESULT_NS_IMPL::result<void, E>::result(result<U,E2>&& other)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value)
+ : m_storage(detail::unit{})
+{
+ m_storage.construct_error_from_result(
+ static_cast<result<U,E2>&&>(other).m_storage
+ );
+}
+
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result(in_place_t)
+ noexcept
+ : m_storage(in_place)
+{
+
+}
+
+template <typename E>
+template <typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result(in_place_error_t, Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, Args...>::value)
+ : m_storage(in_place_error, detail::forward<Args>(args)...)
+{
+
+}
+
+template <typename E>
+template <typename U, typename...Args, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result(in_place_error_t,
+ std::initializer_list<U> ilist,
+ Args&&...args)
+ noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value)
+ : m_storage(in_place_error, ilist, detail::forward<Args>(args)...)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result(const failure<E2>& e)
+ noexcept(std::is_nothrow_constructible<E,const E2&>::value)
+ : m_storage(in_place_error, e.error())
+{
+
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::result(failure<E2>&& e)
+ noexcept(std::is_nothrow_constructible<E,E2&&>::value)
+ : m_storage(in_place_error, static_cast<E2&&>(e.error()))
+{
+
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<void, E>::operator=(const result<void,E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value)
+ -> result&
+{
+ m_storage.assign_from_result(other.m_storage);
+ return (*this);
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<void, E>::operator=(result<void,E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value)
+ -> result&
+{
+ m_storage.assign_from_result(static_cast<result<void,E2>&&>(other).m_storage);
+ return (*this);
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<void, E>::operator=(const failure<E2>& other)
+ noexcept(std::is_nothrow_assignable<E, const E2&>::value)
+ -> result&
+{
+ m_storage.assign_error(other.error());
+ return (*this);
+}
+
+template <typename E>
+template <typename E2, typename>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::result<void, E>::operator=(failure<E2>&& other)
+ noexcept(std::is_nothrow_assignable<E, E2&&>::value)
+ -> result&
+{
+ m_storage.assign_error(static_cast<E2&&>(other.error()));
+ return (*this);
+}
+
+//-----------------------------------------------------------------------------
+// Observers
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+RESULT_NS_IMPL::result<void, E>::operator bool()
+ const noexcept
+{
+ return has_value();
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::has_value()
+ const noexcept -> bool
+{
+ return m_storage.storage.m_has_value;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::has_error()
+ const noexcept -> bool
+{
+ return !has_value();
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::value()
+ const & -> void
+{
+ static_cast<void>(
+ has_value() ||
+ (detail::throw_bad_result_access(m_storage.storage.m_error), true)
+ );
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::value()
+ && -> void
+{
+ static_cast<void>(
+ has_value() ||
+ (detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true)
+ );
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::error()
+ const &
+ noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E
+{
+ return has_value() ? E{} : m_storage.storage.m_error;
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::error()
+ && noexcept(std::is_nothrow_constructible<E>::value &&
+ std::is_nothrow_copy_constructible<E>::value) -> E
+{
+ return has_value() ? E{} : static_cast<E&&>(m_storage.storage.m_error);
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void,E>::expect(String&& message)
+ const & -> void
+{
+ if (has_error()) {
+ detail::throw_bad_result_access_message(
+ detail::forward<String>(message),
+ m_storage.storage.m_error
+ );
+ }
+}
+
+template <typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void,E>::expect(String&& message)
+ && -> void
+{
+ if (has_error()) {
+ detail::throw_bad_result_access_message(
+ detail::forward<String>(message),
+ static_cast<E&&>(m_storage.storage.m_error)
+ );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Monadic Functionalities
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::error_or(U&& default_error)
+ const & -> error_type
+{
+ return has_value()
+ ? detail::forward<U>(default_error)
+ : m_storage.storage.m_error;
+}
+
+template <typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::error_or(U&& default_error)
+ && -> error_type
+{
+ return has_value()
+ ? detail::forward<U>(default_error)
+ : static_cast<E&&>(m_storage.storage.m_error);
+}
+
+template <typename E>
+template <typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::and_then(U&& value)
+ const -> result<typename std::decay<U>::type,E>
+{
+ return map([&value]{
+ return detail::forward<U>(value);
+ });
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::flat_map(Fn&& fn)
+ const & -> detail::invoke_result_t<Fn>
+{
+ using result_type = detail::invoke_result_t<Fn>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? detail::invoke(detail::forward<Fn>(fn))
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::flat_map(Fn&& fn)
+ && -> detail::invoke_result_t<Fn>
+{
+ using result_type = detail::invoke_result_t<Fn>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map must return a result type or the program is ill-formed"
+ );
+
+ return has_value()
+ ? detail::invoke(detail::forward<Fn>(fn))
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::map(Fn&& fn)
+ const & -> result<detail::invoke_result_t<Fn>,E>
+{
+ using result_type = detail::invoke_result_t<Fn>;
+
+ return map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn));
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::map(Fn&& fn)
+ && -> result<detail::invoke_result_t<Fn>,E>
+{
+ using result_type = detail::invoke_result_t<Fn>;
+
+ return static_cast<result<void,E>&&>(*this).map_impl(
+ std::is_void<result_type>{},
+ detail::forward<Fn>(fn)
+ );
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::map_error(Fn&& fn)
+ const & -> result<void, detail::invoke_result_t<Fn,const E&>>
+{
+ using result_type = result<void, detail::invoke_result_t<Fn, const E&>>;
+
+ return has_value()
+ ? result_type{}
+ : result_type(in_place_error, detail::invoke(
+ detail::forward<Fn>(fn), m_storage.storage.m_error
+ ));
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::map_error(Fn&& fn)
+ && -> result<void, detail::invoke_result_t<Fn,E&&>>
+{
+ using result_type = result<void, detail::invoke_result_t<Fn, E&&>>;
+
+ return has_value()
+ ? result_type{}
+ : result_type(in_place_error,
+ detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error)
+ ));
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::flat_map_error(Fn&& fn)
+ const & -> detail::invoke_result_t<Fn,const E&>
+{
+ using result_type = detail::invoke_result_t<Fn,const E&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map_error must return a result type or the program is ill-formed"
+ );
+ static_assert(
+ std::is_default_constructible<typename result_type::value_type>::value,
+ "flat_map_error for result<void,E> requires the new T type to be default-"
+ "constructible"
+ );
+
+ return has_value()
+ ? result_type{}
+ : detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error);
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::flat_map_error(Fn&& fn)
+ && -> detail::invoke_result_t<Fn,E&&>
+{
+ using result_type = detail::invoke_result_t<Fn,E&&>;
+
+ static_assert(
+ is_result<result_type>::value,
+ "flat_map_error must return a result type or the program is ill-formed"
+ );
+ static_assert(
+ std::is_default_constructible<typename result_type::value_type>::value,
+ "flat_map_error for result<void,E> requires the new T type to be default-"
+ "constructible"
+ );
+
+ return has_value()
+ ? result_type{}
+ : detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error));
+}
+
+//-----------------------------------------------------------------------------
+// Private Monadic Functions
+//-----------------------------------------------------------------------------
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::map_impl(std::true_type, Fn&& fn)
+ const & -> result<void,E>
+{
+ using result_type = result<void, E>;
+
+ return has_value()
+ ? (detail::invoke(detail::forward<Fn>(fn)), result_type{})
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::result<void, E>::map_impl(std::false_type, Fn&& fn)
+ const & -> result<detail::invoke_result_t<Fn>,E>
+{
+ using invoke_result_type = detail::invoke_result_t<Fn>;
+ using result_type = result<invoke_result_type, E>;
+
+ return has_value()
+ ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn)))
+ : result_type(in_place_error, m_storage.storage.m_error);
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::map_impl(std::true_type, Fn&& fn)
+ && -> result<void,E>
+{
+ using result_type = result<void, E>;
+
+ return has_value()
+ ? (detail::invoke(detail::forward<Fn>(fn)), result_type{})
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+template <typename E>
+template <typename Fn>
+inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<void, E>::map_impl(std::false_type, Fn&& fn)
+ && -> result<detail::invoke_result_t<Fn>,E>
+{
+ using invoke_result_type = detail::invoke_result_t<Fn>;
+ using result_type = result<invoke_result_type, E>;
+
+ return has_value()
+ ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn)))
+ : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error));
+}
+
+//=============================================================================
+// non-member functions : class : result
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Comparison
+//-----------------------------------------------------------------------------
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs == *rhs
+ : detail::extract_error(lhs) == detail::extract_error(rhs)
+ )
+ : false;
+}
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs != *rhs
+ : detail::extract_error(lhs) != detail::extract_error(rhs)
+ )
+ : true;
+}
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs >= *rhs
+ : detail::extract_error(lhs) >= detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) >= static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs <= *rhs
+ : detail::extract_error(lhs) <= detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) <= static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs > *rhs
+ : detail::extract_error(lhs) > detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) > static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename T1, typename E1, typename T2, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const result<T1,E1>& lhs,
+ const result<T2,E2>& rhs)
+ noexcept -> bool
+{
+ return (lhs.has_value() == rhs.has_value())
+ ? (
+ lhs.has_value()
+ ? *lhs < *rhs
+ : detail::extract_error(lhs) < detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) < static_cast<int>(static_cast<bool>(rhs));
+}
+
+
+//-----------------------------------------------------------------------------
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? true
+ : detail::extract_error(lhs) == detail::extract_error(rhs)
+ )
+ : false;
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? false
+ : detail::extract_error(lhs) != detail::extract_error(rhs)
+ )
+ : true;
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? true
+ : detail::extract_error(lhs) >= detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) >= static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? true
+ : detail::extract_error(lhs) <= detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) <= static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? false
+ : detail::extract_error(lhs) > detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) > static_cast<int>(static_cast<bool>(rhs));
+}
+
+template <typename E1, typename E2>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const result<void,E1>& lhs,
+ const result<void,E2>& rhs)
+ noexcept -> bool
+{
+ return lhs.has_value() == rhs.has_value()
+ ? (
+ lhs.has_value()
+ ? false
+ : detail::extract_error(lhs) < detail::extract_error(rhs)
+ )
+ : static_cast<int>(static_cast<bool>(lhs)) < static_cast<int>(static_cast<bool>(rhs));
+}
+
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return (exp.has_value() && *exp == value);
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return (exp.has_value() && *exp == value);
+}
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return exp.has_value() ? *exp != value : true;
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return exp.has_value() ? value != *exp : true;
+}
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return exp.has_value() ? *exp <= value : false;
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return exp.has_value() ? value <= *exp : true;
+}
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return exp.has_value() ? *exp >= value : true;
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return exp.has_value() ? value >= *exp : false;
+}
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return exp.has_value() ? *exp < value : false;
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return exp.has_value() ? value < *exp : true;
+}
+
+template <typename T, typename E, typename U, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const result<T,E>& exp, const U& value)
+ noexcept -> bool
+{
+ return exp.has_value() ? *exp > value : false;
+}
+
+template <typename T, typename U, typename E, typename>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const T& value, const result<U,E>& exp)
+ noexcept -> bool
+{
+ return exp.has_value() ? value > *exp : true;
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) == error.error() : false;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator==(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() == detail::extract_error(exp) : false;
+}
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) != error.error() : true;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator!=(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() != detail::extract_error(exp) : true;
+}
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) <= error.error() : true;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<=(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() <= detail::extract_error(exp) : false;
+}
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) >= error.error() : false;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>=(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() >= detail::extract_error(exp) : true;
+}
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) < error.error() : true;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator<(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() < detail::extract_error(exp) : false;
+}
+
+template <typename T, typename E, typename U>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const result<T,E>& exp, const failure<U>& error)
+ noexcept -> bool
+{
+ return exp.has_error() ? detail::extract_error(exp) > error.error() : false;
+}
+
+template <typename T, typename U, typename E>
+inline RESULT_INLINE_VISIBILITY constexpr
+auto RESULT_NS_IMPL::operator>(const failure<T>& error, const result<E,U>& exp)
+ noexcept -> bool
+{
+ return exp.has_error() ? error.error() > detail::extract_error(exp) : true;
+}
+
+//-----------------------------------------------------------------------------
+// Utilities
+//-----------------------------------------------------------------------------
+
+template <typename T, typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::swap(result<T,E>& lhs, result<T,E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_move_constructible<result<T,E>>::value &&
+ std::is_nothrow_move_assignable<result<T,E>>::value &&
+ std::is_nothrow_swappable<T>::value &&
+ std::is_nothrow_swappable<E>::value)
+#else
+ noexcept(std::is_nothrow_move_constructible<result<T,E>>::value &&
+ std::is_nothrow_move_assignable<result<T,E>>::value)
+#endif
+ -> void
+{
+ using std::swap;
+
+ if (lhs.has_value() == rhs.has_value()) {
+ if (lhs.has_value()) {
+ swap(*lhs, *rhs);
+ } else {
+ auto& lhs_error = detail::result_error_extractor::get(lhs);
+ auto& rhs_error = detail::result_error_extractor::get(rhs);
+
+ swap(lhs_error, rhs_error);
+ }
+ // If both `result`s contain values, do nothing
+ } else {
+ auto temp = static_cast<result<T,E>&&>(lhs);
+ lhs = static_cast<result<T,E>&&>(rhs);
+ rhs = static_cast<result<T,E>&&>(temp);
+ }
+}
+
+template <typename E>
+inline RESULT_INLINE_VISIBILITY
+auto RESULT_NS_IMPL::swap(result<void,E>& lhs, result<void,E>& rhs)
+#if __cplusplus >= 201703L
+ noexcept(std::is_nothrow_move_constructible<result<void,E>>::value &&
+ std::is_nothrow_move_assignable<result<void,E>>::value &&
+ std::is_nothrow_swappable<E>::value)
+#else
+ noexcept(std::is_nothrow_move_constructible<result<void,E>>::value &&
+ std::is_nothrow_move_assignable<result<void,E>>::value)
+#endif
+ -> void
+{
+ using std::swap;
+
+ if (lhs.has_value() == rhs.has_value()) {
+ if (lhs.has_error()) {
+ auto& lhs_error = detail::result_error_extractor::get(lhs);
+ auto& rhs_error = detail::result_error_extractor::get(rhs);
+
+ swap(lhs_error, rhs_error);
+ }
+ // If both `result`s contain values, do nothing
+ } else {
+ auto temp = static_cast<result<void,E>&&>(lhs);
+ lhs = static_cast<result<void,E>&&>(rhs);
+ rhs = static_cast<result<void,E>&&>(temp);
+ }
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+#undef RESULT_NAMESPACE_INTERNAL
+#undef RESULT_NS_IMPL
+#undef RESULT_CPP14_CONSTEXPR
+#undef RESULT_CPP17_INLINE
+#undef RESULT_INLINE_VISIBILITY
+#undef RESULT_NODISCARD
+#undef RESULT_WARN_UNUSED
+
+#endif /* RESULT_RESULT_HPP */