From 0803f83355e5ad1cd5f321fdc8a927a2939af022 Mon Sep 17 00:00:00 2001
From: altalk23 <45172705+altalk23@users.noreply.github.com>
Date: Fri, 2 Dec 2022 18:40:51 +0300
Subject: [PATCH] completely replace result impl - TODO: fix unzip

---
 .clang-format                                 |    3 +-
 bindings/Cocos2d.bro                          |    1 +
 loader/include/Geode/c++stl/gdlib.hpp         |  153 +
 loader/include/Geode/c++stl/gnustl.hpp        |  172 +-
 .../include/Geode/external/result/result.hpp  | 5994 +++++++++++++++++
 loader/include/Geode/utils/Result.hpp         |  408 +-
 loader/src/loader/Hook.cpp                    |    2 +-
 loader/src/loader/ModInfo.cpp                 |    4 +-
 loader/src/loader/Patch.cpp                   |    2 +-
 loader/src/platform/mac/Cocos2d.cpp           |    4 -
 loader/src/ui/nodes/Notification.cpp          |   37 +-
 loader/src/utils/file.cpp                     |   32 +-
 12 files changed, 6442 insertions(+), 370 deletions(-)
 create mode 100644 loader/include/Geode/c++stl/gdlib.hpp
 create mode 100644 loader/include/Geode/external/result/result.hpp

diff --git a/.clang-format b/.clang-format
index 48451bcf..974e428d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -84,7 +84,7 @@ IndentCaseLabels: true
 IndentExternBlock: Indent
 IndentGotoLabels: true
 IndentPPDirectives: BeforeHash
-IndentRequiresClause: false
+IndentRequiresClause: true
 IndentWrappedFunctionNames: false
 # InsertBraces: true
 InsertTrailingCommas: None
@@ -101,6 +101,7 @@ PenaltyBreakBeforeFirstCallParameter: 19
 PenaltyBreakComment: 300
 PenaltyBreakFirstLessLess: 120
 PenaltyBreakString: 1000
+PenaltyBreakOpenParenthesis: 0
 PenaltyBreakTemplateDeclaration: 10
 PenaltyExcessCharacter: 1000000
 PenaltyReturnTypeOnItsOwnLine: 1000000
diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro
index 71644c07..21cfb16e 100644
--- a/bindings/Cocos2d.bro
+++ b/bindings/Cocos2d.bro
@@ -210,6 +210,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo {
     virtual void addSearchPath(const char* path);
 	virtual void removeSearchPath(const char *path);
     virtual std::string fullPathForFilename(const char* filename, bool unk);
+    void removeAllPaths() = mac 0x241600;
 }
 
 class cocos2d::CCGLProgram {
diff --git a/loader/include/Geode/c++stl/gdlib.hpp b/loader/include/Geode/c++stl/gdlib.hpp
new file mode 100644
index 00000000..9e0e6fc6
--- /dev/null
+++ b/loader/include/Geode/c++stl/gdlib.hpp
@@ -0,0 +1,153 @@
+#pragma once
+
+#include <cstdint>
+#include <array>
+
+namespace geode::stl {
+
+	template <class Type>
+	class AllocatorTemplate {
+	protected:
+		inline Type* allocate(size_t count);
+		inline void deallocate(Type* pointer);
+	};
+
+#if defined(GEODE_IS_WINDOWS)
+	template <class Type>
+	class AllocatorBase {
+	protected:
+		inline Type* allocate(size_t count) {
+
+		}
+		inline void deallocate(Type* pointer) {
+
+		}
+	};
+#elif defined(GEODE_IS_MACOS) || defined(GEODE_IS_ANDROID)
+
+#elif defined(GEODE_IS_IOS)
+
+#endif
+
+
+	class StringTemplate : public AllocatorBase {
+	protected:
+		// depends on already set size and capacity
+		inline void setStorage(char* pointer) = delete;
+		inline char* getStorage() = delete;
+
+		inline void setSize(size_t size) = delete;
+		inline size_t getSize() = delete;
+
+		inline void setCapacity(size_t capacity) = delete;
+		inline size_t getCapacity() = delete;
+	};
+
+#if defined(GEODE_IS_WINDOWS)
+	class StringBase : public StringTemplate {
+	protected:
+		union {
+			std::array<char, 16> m_smallStorage;
+			char* m_bigStorage;
+		};
+
+		size_t m_size;
+		size_t m_capacity;
+
+		inline void setStorage(char* storage) {
+			if (m_capacity > 15) {
+				return m_bigStorage = storage;
+			}
+		}
+		inline char* getStorage() {
+			if (m_capacity > 15) {
+				return m_bigStorage;
+			}
+			return m_smallStorage.data();
+		}
+
+		inline void setSize(size_t size) {
+			m_size = size;
+		}
+		inline size_t getSize() {
+			return m_size;
+		}
+
+		inline void setCapacity(size_t capacity) {
+			m_capacity = capacity;
+		}
+		inline size_t getCapacity() {
+			return m_capacity;
+		}
+	};
+#elif defined(GEODE_IS_MACOS) || defined(GEODE_IS_ANDROID)
+	class StringBase : public StringTemplate {
+	protected:
+		char* m_storage;
+		size_t m_size;
+		size_t m_capacity;
+
+		inline void setStorage(char* storage) {
+			m_storage = storage;
+		}
+		inline char* getStorage() {
+			return m_storage;
+		}
+
+		inline void setSize(size_t size) {
+			m_size = size;
+		}
+		inline size_t getSize() {
+			return m_size;
+		}
+
+		inline void setCapacity(size_t capacity) {
+			m_capacity = capacity;
+		}
+		inline size_t getCapacity() {
+			return m_capacity;
+		}
+	};
+#elif defined(GEODE_IS_IOS)
+	class StringBase : public StringTemplate {
+	protected:
+		struct Short {
+			uint8_t sizex2;
+			std::array<char, 23> shortStorage;
+		};
+
+		struct Long {
+			size_t capacitym1;
+			size_t size;
+			char* longStorage;
+		};
+
+		union {
+			Short m_short;
+			Long m_long;
+		};
+
+		inline void setStorage(char* storage) {
+			m_storage = storage;
+		}
+		inline char* getStorage() {
+			return m_storage;
+		}
+
+		inline void setSize(size_t size) {
+			m_size = size;
+		}
+		inline size_t getSize() {
+			return m_size;
+		}
+
+		inline void setCapacity(size_t capacity) {
+			m_capacity = capacity;
+		}
+		inline size_t getCapacity() {
+			return m_capacity;
+		}
+	};
+#endif
+
+}
\ No newline at end of file
diff --git a/loader/include/Geode/c++stl/gnustl.hpp b/loader/include/Geode/c++stl/gnustl.hpp
index 5f0856ed..f6d67acb 100644
--- a/loader/include/Geode/c++stl/gnustl.hpp
+++ b/loader/include/Geode/c++stl/gnustl.hpp
@@ -296,68 +296,88 @@ namespace gd {
         }
     };
 
+    // template <class Type>
+    // using vector = std::vector<Type>;
+
     template <typename T>
     class GEODE_DLL vector {
     public:
         using value_type = T;
 
-        operator std::vector<T>() const {
-            std::vector<T> out;
-
-            for (auto i = m_start; i != m_finish; ++i) {
-                out.push_back(*i);
-            }
-            return out;
+        auto allocator() const {
+            return std::allocator<T>();
         }
 
-        vector(std::vector<T> input) {
-            std::allocator<T> alloc;
-            auto tmp = alloc.allocate(input.size());
+        operator std::vector<T>() const {
+            return std::vector<T>(m_start, m_finish);
+        }
 
-            m_start = tmp;
+        vector(std::vector<T> const& input) {
+            m_start = this->allocator().allocate(input.size());
             m_finish = m_start + input.size();
-            m_capacity_end = m_start + input.size();
-            for (auto i : input) {
-                *tmp = i;
-                tmp++;
-            }
+            m_reserveEnd = m_start + input.size();
+
+            std::copy(input.begin(), input.end(), m_start);
         }
 
         vector(std::initializer_list<T> const& input) {
-            std::allocator<T> alloc;
-            auto tmp = alloc.allocate(input.size());
-            m_start = tmp;
+            m_start = this->allocator().allocate(input.size());
             m_finish = m_start + input.size();
-            m_capacity_end = m_start + input.size();
-            std::copy(input.begin(), input.end(), tmp);
+            m_reserveEnd = m_start + input.size();
+
+            std::copy(input.begin(), input.end(), m_start);
         }
         
         void clear() {
-            std::allocator<T> alloc;
-            alloc.deallocate(m_start, (m_finish - m_start) / 8);
-            m_start = alloc.allocate(1);
+            std::destroy(m_start, m_finish);
+
+            this->allocator().deallocate(m_start, this->size());
+
+            m_start = this->allocator().allocate(16);
             m_finish = m_start;
-            m_capacity_end = m_start + 8;
+            m_reserveEnd = m_start;
+        }
+
+        T& operator[](size_t index) {
+            return m_start[index];
+        }
+
+        T const& operator[](size_t index) const {
+            return m_start[index];
+        }
+
+        T& at(size_t index) {
+            if (index >= this->size()) {
+                throw std::out_of_range("gd::vector::at");
+            }
+            return m_start[index];
+        }
+
+        T const& at(size_t index) const {
+            if (index >= this->size()) {
+                throw std::out_of_range("gd::vector::at");
+            }
+            return m_start[index];
         }
 
         T& front() {
             return *m_start;
         }
 
-        auto begin() {
+        T* begin() {
             return m_start;
         }
 
-        auto end() {
+        T* end() {
             return m_finish;
         }
 
-        auto begin() const {
-            return static_cast<const T*>(m_start);
+        T const* begin() const {
+            return m_start;
         }
 
-        auto end() const {
-            return static_cast<const T*>(m_finish);
+        T const* end() const {
+            return m_finish;
         }
 
         vector(vector const& lol) : vector(std::vector<T>(lol)) {}
@@ -370,10 +390,18 @@ namespace gd {
             }
         }
 
+        size_t size() const {
+            return m_finish - m_start;
+        }
+
+        size_t capacity() const {
+            return m_reserveEnd - m_start;
+        }
+
     protected:
         T* m_start;
         T* m_finish;
-        T* m_capacity_end;
+        T* m_reserveEnd;
     };
 
     struct _bit_reference {
@@ -436,55 +464,55 @@ namespace gd {
         }
     };
 
-    template <>
-    class vector<bool> {
-    protected:
-        _bit_iterator m_start;
-        _bit_iterator m_end;
-        uintptr_t* m_capacity_end;
+    // template <>
+    // class vector<bool> {
+    // protected:
+    //     _bit_iterator m_start;
+    //     _bit_iterator m_end;
+    //     uintptr_t* m_capacity_end;
 
-    public:
-        vector(std::vector<bool> input) : m_start(0), m_end(0) {
-            auto realsize = input.size() / int(sizeof(uintptr_t));
-            auto tmp = new uintptr_t[realsize];
+    // public:
+    //     vector(std::vector<bool> input) : m_start(0), m_end(0) {
+    //         auto realsize = input.size() / int(sizeof(uintptr_t));
+    //         auto tmp = new uintptr_t[realsize];
 
-            m_start = _bit_iterator(tmp);
-            m_end = _bit_iterator(tmp + realsize, input.size() % sizeof(uintptr_t));
-            m_capacity_end = tmp + realsize;
+    //         m_start = _bit_iterator(tmp);
+    //         m_end = _bit_iterator(tmp + realsize, input.size() % sizeof(uintptr_t));
+    //         m_capacity_end = tmp + realsize;
 
-            auto itmp = m_start;
-            for (auto i : input) {
-                *itmp = i;
-                ++itmp;
-            }
-        }
+    //         auto itmp = m_start;
+    //         for (auto i : input) {
+    //             *itmp = i;
+    //             ++itmp;
+    //         }
+    //     }
 
-        vector(vector<bool> const& lol) : vector(std::vector<bool>(lol)) {}
+    //     vector(vector<bool> const& lol) : vector(std::vector<bool>(lol)) {}
 
-        vector() : vector(std::vector<bool>()) {}
+    //     vector() : vector(std::vector<bool>()) {}
 
-        ~vector() {
-            delete[] m_start.m_bitptr;
-        }
+    //     ~vector() {
+    //         delete[] m_start.m_bitptr;
+    //     }
 
-        operator std::vector<bool>() const {
-            std::vector<bool> out;
-            for (auto i = m_start; i != m_end; ++i) {
-                out.push_back(*i);
-            }
-            return out;
-        }
+    //     operator std::vector<bool>() const {
+    //         std::vector<bool> out;
+    //         for (auto i = m_start; i != m_end; ++i) {
+    //             out.push_back(*i);
+    //         }
+    //         return out;
+    //     }
 
-        _bit_reference operator[](size_t index) {
-            const auto real_index = index / sizeof(uintptr_t);
-            const auto offset = index % sizeof(uintptr_t);
-            return _bit_reference(&m_start.m_bitptr[real_index], 1UL << offset);
-        }
+    //     _bit_reference operator[](size_t index) {
+    //         const auto real_index = index / sizeof(uintptr_t);
+    //         const auto offset = index % sizeof(uintptr_t);
+    //         return _bit_reference(&m_start.m_bitptr[real_index], 1UL << offset);
+    //     }
 
-        bool operator[](size_t index) const {
-            return const_cast<vector&>(*this)[index];
-        }
-    };
+    //     bool operator[](size_t index) const {
+    //         return const_cast<vector&>(*this)[index];
+    //     }
+    // };
 };
 
 #elif defined(GEODE_IS_IOS)
diff --git a/loader/include/Geode/external/result/result.hpp b/loader/include/Geode/external/result/result.hpp
new file mode 100644
index 00000000..f2ac2802
--- /dev/null
+++ b/loader/include/Geode/external/result/result.hpp
@@ -0,0 +1,5994 @@
+////////////////////////////////////////////////////////////////////////////////
+/// \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
+    ///
+    /// \return the value of `*this`
+    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) & -> typename std::add_lvalue_reference<T>::type;
+    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) && -> typename std::add_rvalue_reference<T>::type;
+    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 & -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type;
+    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 && -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
+    /// \}
+
+    //-------------------------------------------------------------------------
+    // 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)
+  & -> typename std::add_lvalue_reference<T>::type
+{
+  return (has_value() ||
+          (detail::throw_bad_result_access_message(
+                  detail::forward<String>(message),
+                  m_storage.storage.m_error
+          ), true),
+          m_storage.storage.m_value
+  );
+}
+
+template <typename T, typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::expect(String&& message)
+  && -> typename std::add_rvalue_reference<T>::type
+{
+  using reference = typename std::add_rvalue_reference<T>::type;
+
+  return (has_value() ||
+          (detail::throw_bad_result_access_message(
+                  detail::forward<String>(message),
+                  static_cast<E&&>(m_storage.storage.m_error)
+          ), true),
+          static_cast<reference>(m_storage.storage.m_value)
+  );
+}
+
+template <typename T, typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::expect(String&& message)
+  const & -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type
+{
+    return (has_value() ||
+            (detail::throw_bad_result_access_message(
+                    detail::forward<String>(message),
+                    m_storage.storage.m_error
+            ), true),
+            m_storage.storage.m_value
+    );
+}
+
+template <typename T, typename E>
+template <typename String, typename>
+inline RESULT_CPP14_CONSTEXPR
+auto RESULT_NS_IMPL::result<T,E>::expect(String&& message)
+  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_message(
+                    detail::forward<String>(message),
+                    static_cast<const E&&>(m_storage.storage.m_error)
+            ), true),
+            (static_cast<reference>(m_storage.storage.m_value))
+    );
+}
+
+//-----------------------------------------------------------------------------
+// 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 */
\ No newline at end of file
diff --git a/loader/include/Geode/utils/Result.hpp b/loader/include/Geode/utils/Result.hpp
index 56c800b4..4fd2f43b 100644
--- a/loader/include/Geode/utils/Result.hpp
+++ b/loader/include/Geode/utils/Result.hpp
@@ -1,322 +1,234 @@
 #pragma once
 
 #include "../DefaultInclude.hpp"
+#include "../external/result/result.hpp"
 
+#include <fmt/format.h>
 #include <string>
 #include <string_view>
+#include <type_traits>
 #include <variant>
-#include <fmt/format.h>
 
-// clang-format off
+// clang-format on
 
 namespace geode {
-    namespace {
-        struct AnyType {
-            explicit AnyType() = delete;
-        };
-
-        template <class V, class RV>
-        concept ConvertibleToResult =
-            std::is_convertible_v<std::remove_reference_t<V>, std::remove_reference_t<RV>> ||
-            std::is_same_v<std::remove_reference_t<V>, std::remove_reference_t<RV>>;
-
+    namespace impl {
         using DefaultValue = std::monostate;
         using DefaultError = std::string;
+        template <class T>
+        using WrappedResult = std::conditional_t<
+            std::is_lvalue_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>,
+            std::remove_const_t<T>>;
 
-        template<class T, class E>
-        struct Storage {
-            std::variant<T, E> m_value;
+        template <class E = impl::DefaultError>
+        class [[nodiscard]] Failure {
+        public:
+            WrappedResult<E> m_error;
 
-            bool holdsOk() const {
-                return std::holds_alternative<T>(m_value);
+            Failure() = default;
+
+            template <class E2>
+                requires(std::is_constructible_v<E, E2 const&>)
+            explicit constexpr Failure(E2 const& e) : m_error(e) {}
+
+            template <class E2>
+                requires(std::is_constructible_v<E, E2 &&>)
+            explicit constexpr Failure(E2&& e) : m_error(std::forward<E>(e)) {}
+
+            E& error() & noexcept {
+                return m_error;
             }
 
-            T getOk() const requires std::is_copy_constructible_v<T> {
-                return std::get<T>(m_value);
+            E const& error() const& noexcept {
+                return m_error;
             }
 
-            T&& getOk() requires(!std::is_copy_constructible_v<T>) {
-                return std::move(std::get<T>(m_value));
+            E&& error() && noexcept {
+                return static_cast<E&&>(m_error);
             }
 
-            E getErr() const requires std::is_copy_constructible_v<E> {
-                return std::get<E>(m_value);
+            E const&& error() const&& noexcept {
+                return static_cast<E&&>(m_error);
             }
-
-            E&& getErr() requires(!std::is_copy_constructible_v<E>) {
-                return std::move(std::get<E>(m_value));
-            }
-
-            template<class T2, class E2>
-                requires
-                    std::is_convertible_v<T2, T> &&
-                    std::is_convertible_v<E2, E>
-            Storage(Storage<T2, E2> const& other)
-                requires
-                    std::is_copy_constructible_v<T> &&
-                    std::is_copy_constructible_v<E>
-            {
-                if (other.holdsOk()) {
-                    m_value = other.getOk();
-                } else {
-                    m_value = other.getErr();
-                }
-            }
-            
-            Storage(T const& value)
-                requires std::is_copy_constructible_v<T>
-              : m_value(value) {}
-
-            Storage(T&& value)
-                requires std::is_move_constructible_v<T>
-              : m_value(std::forward<T>(value)) {}
-
-            Storage(E const& value, std::monostate)
-                requires std::is_copy_constructible_v<E>
-              : m_value(value) {}
-
-            Storage(E&& value, std::monostate)
-                requires std::is_move_constructible_v<E>
-              : m_value(std::forward<E>(value)) {}
         };
 
-        template<class T>
-        struct Storage<T, T> {
-            bool m_holdsOk;
-            T m_value;
+        template <class T = impl::DefaultValue>
+        class [[nodiscard]] Success {
+        public:
+            WrappedResult<T> m_value;
 
-            bool holdsOk() const {
-                return m_holdsOk;
-            }
+            Success() = default;
 
-            T getOk() const requires std::is_copy_constructible_v<T> {
+            template <class T2>
+                requires(std::is_constructible_v<T, T2 const&>)
+            explicit constexpr Success(T2 const& v) : m_value(v) {}
+
+            template <class T2>
+                requires(std::is_constructible_v<T, T2 &&>)
+            explicit constexpr Success(T2&& v) : m_value(std::forward<T>(v)) {}
+
+            T& value() & noexcept {
                 return m_value;
             }
 
-            T&& getOk() requires(!std::is_copy_constructible_v<T>) {
-                return std::move(m_value);
-            }
-
-            T getErr() const requires std::is_copy_constructible_v<T> {
+            T const& value() const& noexcept {
                 return m_value;
             }
 
-            T&& getErr() requires(!std::is_copy_constructible_v<T>) {
-                return std::move(m_value);
+            T&& value() && noexcept {
+                return static_cast<T&&>(m_value);
             }
 
-            template<class T2, class E2>
-                requires
-                    std::is_convertible_v<T2, T> &&
-                    std::is_convertible_v<E2, T>
-            Storage(Storage<T2, E2> const& other)
-                requires
-                    std::is_copy_constructible_v<T> &&
-                    std::is_copy_constructible_v<T>
-               : m_value(other.holdsOk() ? other.getOk() : other.getErr()),
-                 m_holdsOk(other.holdsOk()) {}
-            
-            Storage(T const& value)
-                requires std::is_copy_constructible_v<T>
-              : m_value(value),
-                m_holdsOk(true) {}
-
-            Storage(T&& value)
-                requires std::is_move_constructible_v<T>
-              : m_value(std::forward<T>(value)),
-                m_holdsOk(true) {}
-
-            Storage(T const& value, std::monostate)
-                requires std::is_copy_constructible_v<T>
-              : m_value(value),
-                m_holdsOk(false) {}
-
-            Storage(T&& value, std::monostate)
-                requires std::is_move_constructible_v<T>
-              : m_value(std::forward<T>(value)),
-                m_holdsOk(false) {}
+            T const&& value() const&& noexcept {
+                return static_cast<T&&>(m_value);
+            }
         };
     }
 
-    template <class T = DefaultValue, class E = DefaultError>
-    class [[nodiscard]] Result final {
+    template <class T = impl::DefaultValue, class E = impl::DefaultError>
+    class [[nodiscard]] Result : public cpp::result<T, E> {
     public:
-        using value_type = std::remove_reference_t<T>;
-        using error_type = std::remove_reference_t<E>;
+        using Base = cpp::result<T, E>;
+        using ValueType = typename Base::value_type;
+        using ErrorType = typename Base::error_type;
 
-        // for some reason doing requires causes errors with pch...
-        static_assert(
-            std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
-            "T must be copiable or movable!"
-        );
-        static_assert(
-            std::is_copy_constructible_v<error_type> || std::is_move_constructible_v<error_type>,
-            "E must be copiable or movable!"
-        );
+        using Base::result;
 
-    protected:
-        Storage<value_type, error_type> m_value;
+        template <class U>
+            requires(cpp::detail::result_is_implicit_value_convertible<T, U>::value)
+        constexpr Result(U&& value) = delete;
 
-    public:
-        Storage<value_type, error_type> const& _Raw_Storage() const {
-            return m_value;
+        template <class E2>
+            requires(std::is_constructible_v<E, E2 const&>)
+        constexpr Result(impl::Failure<E2> const& e) : Base(cpp::failure<E>(e.error())) {}
+
+        template <class E2>
+            requires(std::is_constructible_v<E, E2 &&>)
+        constexpr Result(impl::Failure<E2>&& e) : Base(cpp::failure<E>(e.error())) {}
+
+        template <class T2>
+            requires(std::is_constructible_v<T, T2 const&>)
+        constexpr Result(impl::Success<T2> const& s) : Base(s.value()) {}
+
+        template <class T2>
+            requires(std::is_constructible_v<T, T2 &&>)
+        constexpr Result(impl::Success<T2>&& s) : Base(s.value()) {}
+
+        [[nodiscard]] constexpr explicit operator bool() const noexcept {
+            return this->operator bool();
         }
 
-        bool isOk() const {
-            return m_value.holdsOk();
+        [[nodiscard]] constexpr bool isOk() const noexcept {
+            return this->has_value();
         }
 
-        bool isErr() const {
-            return !m_value.holdsOk();
+        [[nodiscard]] constexpr bool isErr() const noexcept {
+            return this->has_error();
         }
 
-        template<class ... Args>
-        Result<T, std::string> expect(const char* str, Args&&... args) {
-            if (isErr()) {
-                return Result<T, std::string>(fmt::format(
-                    str,
-                    std::forward<Args>(args)...,
-                    fmt::arg("error", unwrapErr())
-                ), std::monostate());
-            } else {
+        [[nodiscard]] constexpr decltype(auto) unwrap() & {
+            return this->value();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrap() const& {
+            return this->value();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrap() && {
+            return this->value();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrap() const&& {
+            return this->value();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrapErr() & {
+            return this->error();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrapErr() const& {
+            return this->error();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrapErr() && {
+            return this->error();
+        }
+
+        [[nodiscard]] constexpr decltype(auto) unwrapErr() const&& {
+            return this->error();
+        }
+
+        template <class... Args>
+        [[nodiscard]] Result<T, std::string> expect(std::string const& format, Args&&... args)
+            const {
+            if (this->isErr()) {
+                return impl::Failure<std::string>(fmt::format(
+                    fmt::runtime(format), std::forward<Args>(args)...,
+                    fmt::arg("error", this->unwrapErr())
+                ));
+            }
+            else {
                 return *this;
             }
         }
 
-        explicit Result(value_type const& value)
-            requires std::is_copy_constructible_v<value_type>
-          : m_value(value) {}
-
-        explicit Result(value_type&& value)
-            requires std::is_move_constructible_v<value_type>
-          : m_value(std::forward<value_type>(value)) {}
-
-        explicit Result(error_type const& value, std::monostate)
-            requires std::is_copy_constructible_v<error_type>
-          : m_value(value, std::monostate()) {}
-
-        explicit Result(error_type&& value, std::monostate)
-            requires std::is_move_constructible_v<error_type>
-          : m_value(std::forward<error_type>(value), std::monostate()) {}
-
-        Result(Result<T, E> const& other)
-            requires
-                std::is_copy_constructible_v<value_type> &&
-                std::is_copy_constructible_v<error_type>
-            = default;
-
-        Result(Result<T, E>&& other)
-            requires(
-                !std::is_copy_constructible_v<value_type> ||
-                !std::is_copy_constructible_v<error_type>
-            ) = default;
-
-        template<class T2, class E2>
-            requires
-                std::is_convertible_v<T2, T> &&
-                std::is_convertible_v<E2, E>
-        Result(Result<T2, E2> const& other)
-            requires
-                std::is_copy_constructible_v<value_type> &&
-                std::is_copy_constructible_v<error_type>
-          : m_value(other._Raw_Storage()) {}
-
-        template <class T2>
-            requires ConvertibleToResult<T2, T>
-        Result(Result<T2, AnyType> const& other)
-            requires
-                std::is_copy_constructible_v<value_type> &&
-                std::is_copy_constructible_v<error_type>
-          : Result(value_type(other.unwrap())) {}
-
-        template <class E2>
-            requires ConvertibleToResult<E2, E>
-        Result(Result<AnyType, E2> const& other)
-            requires
-                std::is_copy_constructible_v<value_type> &&
-                std::is_copy_constructible_v<error_type>
-          : m_value(std::forward<E2>(other.unwrapErr()), std::monostate()) {}
-
-        template <class T2>
-            requires ConvertibleToResult<T2, T>
-        Result(Result<T2, AnyType>&& other)
-            requires(
-                !std::is_copy_constructible_v<value_type> ||
-                !std::is_copy_constructible_v<error_type>
-            )
-          : m_value(other.unwrap()) {}
-
-        template <class E2>
-            requires ConvertibleToResult<E2, E>
-        Result(Result<AnyType, E2>&& other)
-            requires(
-                !std::is_copy_constructible_v<value_type> ||
-                !std::is_copy_constructible_v<error_type>
-            )
-          : Result(std::forward<error_type>(other.unwrapErr()), std::monostate()) {}
-
-        value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
-            return m_value.getOk();
+        template <class U>
+        [[nodiscard]] constexpr decltype(auto) unwrapOr(U&& val) && {
+            return this->value_or(std::forward<U>(val));
         }
 
-        value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
-            return std::forward<value_type>(m_value.getOk());
+        template <class U>
+        [[nodiscard]] constexpr decltype(auto) unwrapOr(U&& val) const& {
+            return this->value_or(std::forward<U>(val));
         }
 
-        error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
-            return m_value.getErr();
+        template <class U>
+        [[nodiscard]] constexpr decltype(auto) errorOr(U&& val) && {
+            return this->error_or(std::forward<U>(val));
         }
 
-        error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
-            return std::forward<error_type>(m_value.getErr());
-        }
-
-        explicit operator bool() const requires(
-            !std::is_same_v<T, bool> &&
-            !std::is_same_v<E, bool>
-        ) {
-            return this->isOk();
+        template <class U>
+        [[nodiscard]] constexpr decltype(auto) errorOr(U&& val) const& {
+            return this->error_or(std::forward<U>(val));
         }
     };
 
-    template <class T = DefaultValue, class E = AnyType>
-        requires std::is_copy_constructible_v<T>
-    Result<T, E> Ok(T value = T()) {
-        return Result<T, E>(value);
+    template <class T = impl::DefaultValue>
+    constexpr impl::Success<T> Ok() {
+        return impl::Success<T>();
     }
 
-    template <class T = DefaultValue, class E = AnyType>
-        requires(!std::is_copy_constructible_v<T>)
-    Result<T, E> Ok(T&& value) {
-        return Result<T, E>(std::forward<T>(value));
+    template <class T>
+    constexpr impl::Success<T> Ok(T&& value) {
+        return impl::Success<T>(std::forward<T>(value));
     }
 
-    template <class E = DefaultError, class T = AnyType>
-        requires std::is_copy_constructible_v<E>
-    Result<T, E> Err(E error) {
-        return Result<T, E>(error, std::monostate());
+    template <class E>
+    constexpr impl::Failure<E> Err(E&& error) {
+        return impl::Failure<E>(std::forward<E>(error));
     }
 
-    template <class E = DefaultError, class T = AnyType>
-        requires(!std::is_copy_constructible_v<E>)
-    Result<T, E> Err(E&& error) {
-        return Result<T, E>(std::forward<E>(error), std::monostate());
+    template <class... Args>
+    inline impl::Failure<std::string> Err(std::string const& format, Args&&... args) {
+        return impl::Failure<std::string>(
+            fmt::format(fmt::runtime(format), std::forward<Args>(args)...)
+        );
     }
 
-    #define GEODE_UNWRAP_INTO(into, ...)                                            \
+#define GEODE_UNWRAP_INTO(into, ...)                                            \
+    auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__);                   \
+    if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) {                          \
+        return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
+    }                                                                           \
+    into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap())
+
+#define GEODE_UNWRAP(...)                                                           \
+    {                                                                               \
         auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__);                   \
         if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) {                          \
             return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
         }                                                                           \
-        into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap())
-
-    #define GEODE_UNWRAP(...)                                                           \
-        {                                                                               \
-            auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__);                   \
-            if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) {                          \
-                return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
-            }                                                                           \
-        }
+    }
 }
 
 // clang-format on
diff --git a/loader/src/loader/Hook.cpp b/loader/src/loader/Hook.cpp
index 47693bb4..3e61e80d 100644
--- a/loader/src/loader/Hook.cpp
+++ b/loader/src/loader/Hook.cpp
@@ -78,7 +78,7 @@ Result<Hook*> Mod::addHook(Hook* hook) {
     else {
         internalHooks().push_back({ hook, this });
     }
-    return Ok<Hook*>(hook);
+    return Ok(hook);
 }
 
 bool InternalLoader::loadHooks() {
diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp
index a5f2bc4e..c2c9f1e9 100644
--- a/loader/src/loader/ModInfo.cpp
+++ b/loader/src/loader/ModInfo.cpp
@@ -123,7 +123,7 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
     if (schema < Loader::minModVersion()) {
         return Err(
             "[mod.json] is built for an older version (" + schema.toString() +
-            ") of Geode (current: " + Loader::minModVersion().toString() +
+            ") of Geode (current: " + Loader::getVersion().toString() +
             "). Please update the mod to the latest version, "
             "and if the problem persists, contact the developer "
             "to update it."
@@ -132,7 +132,7 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
     if (schema > Loader::maxModVersion()) {
         return Err(
             "[mod.json] is built for a newer version (" + schema.toString() +
-            ") of Geode (current: " + Loader::maxModVersion().toString() +
+            ") of Geode (current: " + Loader::getVersion().toString() +
             "). You need to update Geode in order to use "
             "this mod."
         );
diff --git a/loader/src/loader/Patch.cpp b/loader/src/loader/Patch.cpp
index 99a1b4be..e5175db8 100644
--- a/loader/src/loader/Patch.cpp
+++ b/loader/src/loader/Patch.cpp
@@ -28,7 +28,7 @@ Result<Patch*> Mod::patch(void* address, byte_array data) {
         return Err("Unable to enable patch at " + std::to_string(p->getAddress()));
     }
     m_patches.push_back(p);
-    return Ok<Patch*>(p);
+    return Ok(p);
 }
 
 Result<> Mod::unpatch(Patch* patch) {
diff --git a/loader/src/platform/mac/Cocos2d.cpp b/loader/src/platform/mac/Cocos2d.cpp
index 1eabd25c..16af07d2 100644
--- a/loader/src/platform/mac/Cocos2d.cpp
+++ b/loader/src/platform/mac/Cocos2d.cpp
@@ -5,10 +5,6 @@
 #include <cocos2d.h>
 using namespace cocos2d;
 
-void CCFileUtils::removeAllPaths() {
-    m_searchPathArray.clear();
-}
-
 CCObject* CCObject::copy()
 {
     return copyWithZone(0);
diff --git a/loader/src/ui/nodes/Notification.cpp b/loader/src/ui/nodes/Notification.cpp
index 92f6ffeb..ff53d95a 100644
--- a/loader/src/ui/nodes/Notification.cpp
+++ b/loader/src/ui/nodes/Notification.cpp
@@ -1,20 +1,19 @@
 #include <Geode/binding/LoadingCircle.hpp>
-#include <Geode/ui/Notification.hpp>
 #include <Geode/loader/Mod.hpp>
+#include <Geode/ui/Notification.hpp>
 
 USE_GEODE_NAMESPACE();
 
-constexpr auto NOTIFICATION_FADEIN  = .3f;
+constexpr auto NOTIFICATION_FADEIN = .3f;
 constexpr auto NOTIFICATION_FADEOUT = 1.f;
 
 Ref<CCArray> Notification::s_queue = CCArray::create();
 
 bool Notification::init(std::string const& text, CCSprite* icon, float time) {
-    if (!CCNodeRGBA::init())
-        return false;
-    
+    if (!CCNodeRGBA::init()) return false;
+
     m_time = time;
-    
+
     m_bg = CCScale9Sprite::create("square02b_small.png", { 0, 0, 40, 40 });
     m_bg->setColor({ 0, 0, 0 });
     this->addChild(m_bg);
@@ -48,7 +47,8 @@ void Notification::updateLayout() {
     if (m_icon) {
         m_icon->setPosition({ size.height / 2, size.height / 2 });
         m_label->setPosition(size / 2 + CCSize { spaceForIcon / 2, .0f });
-    } else {
+    }
+    else {
         m_label->setPosition(size / 2);
     }
 }
@@ -73,9 +73,7 @@ CCSprite* Notification::createIcon(NotificationIcon icon) {
 
         case NotificationIcon::Loading: {
             auto icon = CCSprite::create("loadingCircle.png");
-            icon->runAction(CCRepeatForever::create(
-                CCRotateBy::create(1.f, 360.f)
-            ));
+            icon->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
             icon->setBlendFunc({ GL_ONE, GL_ONE });
             return icon;
         } break;
@@ -94,11 +92,7 @@ CCSprite* Notification::createIcon(NotificationIcon icon) {
     }
 }
 
-Notification* Notification::create(
-    std::string const& text,
-    NotificationIcon icon,
-    float time
-) {
+Notification* Notification::create(std::string const& text, NotificationIcon icon, float time) {
     return Notification::create(text, createIcon(icon), time);
 }
 
@@ -125,7 +119,8 @@ void Notification::setIcon(cocos2d::CCSprite* icon) {
     if (m_icon) {
         m_icon->removeFromParent();
     }
-    if (m_icon = icon) {
+    m_icon = icon;
+    if (icon) {
         m_bg->addChild(icon);
     }
     this->updateLayout();
@@ -171,8 +166,7 @@ void Notification::show() {
         CCCallFunc::create(this, callfunc_selector(Notification::animateIn)),
         // wait for fade-in to finish
         CCDelayTime::create(NOTIFICATION_FADEIN),
-        CCCallFunc::create(this, callfunc_selector(Notification::wait)),
-        nullptr
+        CCCallFunc::create(this, callfunc_selector(Notification::wait)), nullptr
     ));
 }
 
@@ -181,8 +175,7 @@ void Notification::wait() {
     if (m_time) {
         this->runAction(CCSequence::create(
             CCDelayTime::create(m_time),
-            CCCallFunc::create(this, callfunc_selector(Notification::hide)),
-            nullptr
+            CCCallFunc::create(this, callfunc_selector(Notification::hide)), nullptr
         ));
     }
 }
@@ -193,8 +186,6 @@ void Notification::hide() {
         CCCallFunc::create(this, callfunc_selector(Notification::animateOut)),
         // wait for fade-out to finish
         CCDelayTime::create(NOTIFICATION_FADEOUT),
-        CCCallFunc::create(this, callfunc_selector(Notification::showNextNotification)),
-        nullptr
+        CCCallFunc::create(this, callfunc_selector(Notification::showNextNotification)), nullptr
     ));
 }
-
diff --git a/loader/src/utils/file.cpp b/loader/src/utils/file.cpp
index 03c0a237..63456092 100644
--- a/loader/src/utils/file.cpp
+++ b/loader/src/utils/file.cpp
@@ -1,11 +1,11 @@
-#include <Geode/utils/file.hpp>
-#include <Geode/utils/string.hpp>
-#include <Geode/utils/map.hpp>
-#include <Geode/loader/Log.hpp>
-#include <fstream>
 #include <../support/zip_support/ZipUtils.h>
 #include <../support/zip_support/ioapi.h>
 #include <../support/zip_support/unzip.h>
+#include <Geode/loader/Log.hpp>
+#include <Geode/utils/file.hpp>
+#include <Geode/utils/map.hpp>
+#include <Geode/utils/string.hpp>
+#include <fstream>
 
 USE_GEODE_NAMESPACE();
 using namespace geode::utils::file;
@@ -147,9 +147,7 @@ public:
         unz_file_info64 fileInfo;
 
         // Read first file
-        if (unzGoToFirstFile64(
-            m_zip, &fileInfo, fileName, sizeof(fileName) - 1
-        )) {
+        if (unzGoToFirstFile64(m_zip, &fileInfo, fileName, sizeof(fileName) - 1)) {
             return false;
         }
         // Loop over all files
@@ -157,18 +155,15 @@ public:
             // Read file and add to entries
             unz_file_pos pos;
             if (unzGetFilePos(m_zip, &pos) == UNZ_OK) {
-                m_entries.insert({
-                    fileName, ZipEntry {
-                        .m_pos = pos,
-                        .m_compressedSize = fileInfo.compressed_size,
-                        .m_uncompressedSize = fileInfo.uncompressed_size,
-                    }
-                });
+                m_entries.insert({ fileName,
+                                   ZipEntry {
+                                       .m_pos = pos,
+                                       .m_compressedSize = fileInfo.compressed_size,
+                                       .m_uncompressedSize = fileInfo.uncompressed_size,
+                                   } });
             }
             // Read next file, or break on error
-            if (unzGoToNextFile64(
-                m_zip, &fileInfo, fileName, sizeof(fileName) - 1
-            ) != UNZ_OK) {
+            if (unzGoToNextFile64(m_zip, &fileInfo, fileName, sizeof(fileName) - 1) != UNZ_OK) {
                 break;
             }
         }
@@ -208,6 +203,7 @@ public:
     }
 
     UnzipImpl(unzFile zip, Path const& path) : m_zip(zip), m_zipPath(path) {}
+
     ~UnzipImpl() {
         unzClose(m_zip);
     }