File indexing completed on 2025-02-16 05:12:21
0001 //////////////////////////////////////////////////////////////////////////////// 0002 /// \file result.hpp 0003 /// 0004 /// \brief This header contains the 'result' monadic type for indicating 0005 /// possible error conditions 0006 //////////////////////////////////////////////////////////////////////////////// 0007 0008 /* 0009 The MIT License (MIT) 0010 0011 Copyright (c) 2017-2021 Matthew Rodusek All rights reserved. 0012 0013 Permission is hereby granted, free of charge, to any person obtaining a copy 0014 of this software and associated documentation files (the "Software"), to deal 0015 in the Software without restriction, including without limitation the rights 0016 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0017 copies of the Software, and to permit persons to whom the Software is 0018 furnished to do so, subject to the following conditions: 0019 0020 The above copyright notice and this permission notice shall be included in 0021 all copies or substantial portions of the Software. 0022 0023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0024 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0025 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0026 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0027 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 0028 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 0029 SOFTWARE. 0030 */ 0031 0032 #ifndef RESULT_RESULT_HPP 0033 #define RESULT_RESULT_HPP 0034 0035 #include <cstddef> // std::size_t 0036 #include <functional> // std::reference_wrapper, std::invoke 0037 #include <initializer_list> // std::initializer_list 0038 #include <memory> // std::address_of 0039 #include <new> // placement-new 0040 #include <string> // std::string (for exception message) 0041 #include <type_traits> // std::enable_if, std::is_constructible, etc 0042 #include <utility> // std::in_place_t, std::forward 0043 0044 #if defined(RESULT_EXCEPTIONS_DISABLED) 0045 #include <cstdio> // std::fprintf, stderr 0046 #else 0047 #include <stdexcept> // std::logic_error 0048 #endif 0049 0050 #if __cplusplus >= 201402L 0051 #define RESULT_CPP14_CONSTEXPR constexpr 0052 #else 0053 #define RESULT_CPP14_CONSTEXPR 0054 #endif 0055 0056 #if __cplusplus >= 201703L 0057 #define RESULT_CPP17_INLINE inline 0058 #else 0059 #define RESULT_CPP17_INLINE 0060 #endif 0061 0062 #if defined(__clang__) && defined(_MSC_VER) 0063 #define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden"))) 0064 #elif defined(__clang__) || defined(__GNUC__) 0065 #define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden"), always_inline)) 0066 #elif defined(_MSC_VER) 0067 #define RESULT_INLINE_VISIBILITY __forceinline 0068 #else 0069 #define RESULT_INLINE_VISIBILITY 0070 #endif 0071 0072 // [[clang::warn_unused_result]] is more full-featured than gcc's variant, since 0073 // it supports being applied to class objects. 0074 #if __cplusplus >= 201703L 0075 #define RESULT_NODISCARD [[nodiscard]] 0076 #define RESULT_WARN_UNUSED [[nodiscard]] 0077 #elif defined(__clang__) && ((__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 9))) 0078 #define RESULT_NODISCARD [[clang::warn_unused_result]] 0079 #define RESULT_WARN_UNUSED [[clang::warn_unused_result]] 0080 #elif defined(__GNUC__) 0081 #define RESULT_NODISCARD 0082 #define RESULT_WARN_UNUSED [[gnu::warn_unused_result]] 0083 #else 0084 #define RESULT_WARN_UNUSED 0085 #define RESULT_NODISCARD 0086 #endif 0087 0088 #if defined(RESULT_NAMESPACE) 0089 #define RESULT_NAMESPACE_INTERNAL RESULT_NAMESPACE 0090 #else 0091 #define RESULT_NAMESPACE_INTERNAL cpp 0092 #endif 0093 #define RESULT_NS_IMPL RESULT_NAMESPACE_INTERNAL::bitwizeshift 0094 0095 // clang's `-Wdocumentation-unknown-command` flag is bugged and does not 0096 // understand `\copydoc` tags, despite this being a valid doxygen tag. 0097 #if defined(__clang__) 0098 #pragma clang diagnostic push 0099 #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" 0100 #endif 0101 0102 namespace RESULT_NAMESPACE_INTERNAL { 0103 inline namespace bitwizeshift { 0104 0105 //=========================================================================== 0106 // utilities : constexpr forward 0107 //=========================================================================== 0108 0109 // std::forward is not constexpr until C++14 0110 namespace detail { 0111 #if __cplusplus >= 201402L 0112 using std::forward; 0113 #else 0114 template<typename T> 0115 inline RESULT_INLINE_VISIBILITY constexpr auto forward(typename std::remove_reference<T>::type& t) noexcept -> T&& 0116 { 0117 return static_cast<T&&>(t); 0118 } 0119 0120 template<typename T> 0121 inline RESULT_INLINE_VISIBILITY constexpr auto forward(typename std::remove_reference<T>::type&& t) noexcept -> T&& 0122 { 0123 return static_cast<T&&>(t); 0124 } 0125 #endif 0126 } // namespace detail 0127 0128 //=========================================================================== 0129 // utilities : invoke / invoke_result 0130 //=========================================================================== 0131 0132 // std::invoke was introduced in C++17 0133 0134 namespace detail { 0135 #if __cplusplus >= 201703L 0136 using std::invoke; 0137 using std::invoke_result; 0138 using std::invoke_result_t; 0139 #else 0140 template<typename T> 0141 struct is_reference_wrapper : std::false_type { 0142 }; 0143 0144 template<typename U> 0145 struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type { 0146 }; 0147 0148 //------------------------------------------------------------------------- 0149 0150 template<typename Base, 0151 typename T, 0152 typename Derived, 0153 typename... Args, 0154 typename = typename std::enable_if<std::is_function<T>::value 0155 && std::is_base_of<Base, typename std::decay<Derived>::type>::value>::type> 0156 inline RESULT_INLINE_VISIBILITY constexpr auto invoke(T Base::*pmf, Derived&& ref, Args&&...args) noexcept( 0157 noexcept((::RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmf)(::RESULT_NS_IMPL::detail::forward<Args>(args)...))) 0158 -> decltype((::RESULT_NS_IMPL::detail::forward<Derived>(ref) 0159 .*pmf)(::RESULT_NS_IMPL::detail::forward<Args>(args)...)) 0160 { 0161 return (RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...); 0162 } 0163 0164 template<typename Base, 0165 typename T, 0166 typename RefWrap, 0167 typename... Args, 0168 typename = typename std::enable_if<std::is_function<T>::value 0169 && is_reference_wrapper<typename std::decay<RefWrap>::type>::value>::type> 0170 inline RESULT_INLINE_VISIBILITY constexpr auto 0171 invoke(T Base::*pmf, RefWrap&& ref, Args&&...args) noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...))) 0172 -> decltype((ref.get().*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...)) 0173 { 0174 return (ref.get().*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...); 0175 } 0176 0177 template<typename Base, 0178 typename T, 0179 typename Pointer, 0180 typename... Args, 0181 typename = typename std::enable_if<std::is_function<T>::value 0182 && !is_reference_wrapper<typename std::decay<Pointer>::type>::value 0183 && !std::is_base_of<Base, typename std::decay<Pointer>::type>::value>::type> 0184 inline RESULT_INLINE_VISIBILITY constexpr auto invoke(T Base::*pmf, Pointer&& ptr, Args&&...args) noexcept( 0185 noexcept(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))) 0186 -> decltype(((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...)) 0187 { 0188 return ((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward<Args>(args)...); 0189 } 0190 0191 template<typename Base, 0192 typename T, 0193 typename Derived, 0194 typename = typename std::enable_if<!std::is_function<T>::value 0195 && std::is_base_of<Base, typename std::decay<Derived>::type>::value>::type> 0196 inline RESULT_INLINE_VISIBILITY constexpr auto invoke(T Base::*pmd, 0197 Derived&& ref) noexcept(noexcept(std::forward<Derived>(ref).*pmd)) 0198 -> decltype(RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmd) 0199 { 0200 return RESULT_NS_IMPL::detail::forward<Derived>(ref).*pmd; 0201 } 0202 0203 template<typename Base, 0204 typename T, 0205 typename RefWrap, 0206 typename = typename std::enable_if<!std::is_function<T>::value 0207 && is_reference_wrapper<typename std::decay<RefWrap>::type>::value>::type> 0208 inline RESULT_INLINE_VISIBILITY constexpr auto invoke(T Base::*pmd, RefWrap&& ref) noexcept(noexcept(ref.get().*pmd)) 0209 -> decltype(ref.get().*pmd) 0210 { 0211 return ref.get().*pmd; 0212 } 0213 0214 template<typename Base, 0215 typename T, 0216 typename Pointer, 0217 typename = typename std::enable_if<!std::is_function<T>::value 0218 && !is_reference_wrapper<typename std::decay<Pointer>::type>::value 0219 && !std::is_base_of<Base, typename std::decay<Pointer>::type>::value>::type> 0220 inline RESULT_INLINE_VISIBILITY constexpr auto 0221 invoke(T Base::*pmd, Pointer&& ptr) noexcept(noexcept((*std::forward<Pointer>(ptr)).*pmd)) 0222 -> decltype((*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmd) 0223 { 0224 return (*RESULT_NS_IMPL::detail::forward<Pointer>(ptr)).*pmd; 0225 } 0226 0227 template<typename F, 0228 typename... Args, 0229 typename = typename std::enable_if<!std::is_member_pointer<typename std::decay<F>::type>::value>::type> 0230 inline RESULT_INLINE_VISIBILITY constexpr auto 0231 invoke(F&& f, Args&&...args) noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...))) 0232 -> decltype(RESULT_NS_IMPL::detail::forward<F>(f)(RESULT_NS_IMPL::detail::forward<Args>(args)...)) 0233 { 0234 return RESULT_NS_IMPL::detail::forward<F>(f)(RESULT_NS_IMPL::detail::forward<Args>(args)...); 0235 } 0236 0237 template<typename Fn, typename... Args> 0238 struct is_invocable { 0239 template<typename Fn2, typename... Args2> 0240 static auto test(Fn2&&, Args2&&...) 0241 -> decltype(invoke(std::declval<Fn2>(), std::declval<Args2>()...), std::true_type{}); 0242 0243 static auto test(...) -> std::false_type; 0244 0245 using type = decltype(test(std::declval<Fn>(), std::declval<Args>()...)); 0246 static constexpr bool value = type::value; 0247 }; 0248 0249 template<bool B, typename Fn, typename... Args> 0250 struct invoke_result_impl { 0251 using type = decltype(RESULT_NS_IMPL::detail::invoke(std::declval<Fn>(), std::declval<Args>()...)); 0252 }; 0253 template<typename Fn, typename... Args> 0254 struct invoke_result_impl<false, Fn, Args...> { 0255 }; 0256 0257 template<typename Fn, typename... Args> 0258 struct invoke_result : invoke_result_impl<is_invocable<Fn, Args...>::value, Fn, Args...> { 0259 }; 0260 0261 template<typename Fn, typename... Args> 0262 using invoke_result_t = typename invoke_result<Fn, Args...>::type; 0263 #endif 0264 } // namespace detail 0265 0266 //=========================================================================== 0267 // struct : in_place_t 0268 //=========================================================================== 0269 0270 #if __cplusplus >= 201703L 0271 using std::in_place; 0272 using std::in_place_t; 0273 #else 0274 /// \brief A structure for representing in-place construction 0275 struct in_place_t { 0276 explicit in_place_t() = default; 0277 }; 0278 RESULT_CPP17_INLINE constexpr auto in_place = in_place_t{}; 0279 #endif 0280 0281 //=========================================================================== 0282 // struct : in_place_t 0283 //=========================================================================== 0284 0285 /// \brief A structure for representing in-place construction of an error type 0286 struct in_place_error_t { 0287 explicit in_place_error_t() = default; 0288 }; 0289 0290 RESULT_CPP17_INLINE constexpr auto in_place_error = in_place_error_t{}; 0291 0292 //=========================================================================== 0293 // forward-declarations 0294 //=========================================================================== 0295 0296 template<typename> 0297 class failure; 0298 0299 template<typename, typename> 0300 class result; 0301 0302 template<typename> 0303 class bad_result_access; 0304 0305 //=========================================================================== 0306 // traits 0307 //=========================================================================== 0308 0309 template<typename T> 0310 struct is_failure : std::false_type { 0311 }; 0312 template<typename E> 0313 struct is_failure<failure<E>> : std::true_type { 0314 }; 0315 0316 template<typename T> 0317 struct is_result : std::false_type { 0318 }; 0319 template<typename T, typename E> 0320 struct is_result<result<T, E>> : std::true_type { 0321 }; 0322 0323 //=========================================================================== 0324 // trait : detail::wrapped_result_type 0325 //=========================================================================== 0326 0327 namespace detail { 0328 0329 template<typename T> 0330 using wrapped_result_type = typename std::conditional<std::is_lvalue_reference<T>::value, 0331 std::reference_wrapper<typename std::remove_reference<T>::type>, 0332 typename std::remove_const<T>::type>::type; 0333 0334 } // namespace detail 0335 0336 #if !defined(RESULT_DISABLE_EXCEPTIONS) 0337 0338 //=========================================================================== 0339 // class : bad_result_access<E> 0340 //=========================================================================== 0341 0342 ///////////////////////////////////////////////////////////////////////////// 0343 /// \brief An exception thrown when result::value is accessed without 0344 /// a contained value 0345 ///////////////////////////////////////////////////////////////////////////// 0346 template<typename E> 0347 class bad_result_access : public std::logic_error { 0348 //------------------------------------------------------------------------- 0349 // Constructor / Assignment 0350 //------------------------------------------------------------------------- 0351 public: 0352 /// \brief Constructs this exception using the underlying error type for 0353 /// the error type 0354 /// 0355 /// \param error the underlying error 0356 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2>::value>::type> 0357 explicit bad_result_access(E2&& error); 0358 0359 /// \{ 0360 /// \brief Constructs this exception using the underlying error type for 0361 /// the error and a message 0362 /// 0363 /// \param what_arg the message for the failure 0364 /// \param error the underlying error 0365 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2>::value>::type> 0366 bad_result_access(const char *what_arg, E2&& error); 0367 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2>::value>::type> 0368 bad_result_access(const std::string& what_arg, E2&& error); 0369 /// \} 0370 0371 bad_result_access(const bad_result_access& other) = default; 0372 bad_result_access(bad_result_access&& other) = default; 0373 0374 //------------------------------------------------------------------------- 0375 0376 auto operator=(const bad_result_access& other) -> bad_result_access& = default; 0377 auto operator=(bad_result_access&& other) -> bad_result_access& = default; 0378 0379 /// \{ 0380 /// \brief Gets the underlying error 0381 /// 0382 /// \return the error 0383 auto error() & noexcept -> E&; 0384 auto error() && noexcept -> E&&; 0385 auto error() const& noexcept -> const E&; 0386 auto error() const&& noexcept -> const E&&; 0387 /// \} 0388 0389 //------------------------------------------------------------------------- 0390 // Private Members 0391 //------------------------------------------------------------------------- 0392 private: 0393 E m_error; 0394 }; 0395 0396 #endif 0397 0398 namespace detail { 0399 0400 template<typename E, typename E2> 0401 using failure_is_value_convertible = std::integral_constant< 0402 bool, 0403 (std::is_constructible<E, E2&&>::value && !std::is_same<typename std::decay<E2>::type, in_place_t>::value 0404 && !is_failure<typename std::decay<E2>::type>::value && !is_result<typename std::decay<E2>::type>::value)>; 0405 0406 template<typename E, typename E2> 0407 using failure_is_explicit_value_convertible = 0408 std::integral_constant<bool, (failure_is_value_convertible<E, E2>::value && !std::is_convertible<E2, E>::value)>; 0409 0410 template<typename E, typename E2> 0411 using failure_is_implicit_value_convertible = 0412 std::integral_constant<bool, (failure_is_value_convertible<E, E2>::value && std::is_convertible<E2, E>::value)>; 0413 0414 template<typename E, typename E2> 0415 using failure_is_value_assignable = std::integral_constant<bool, 0416 (!is_result<typename std::decay<E2>::type>::value 0417 && !is_failure<typename std::decay<E2>::type>::value 0418 && std::is_assignable<wrapped_result_type<E>&, E2>::value)>; 0419 0420 } // namespace detail 0421 0422 //=========================================================================== 0423 // class : failure_type 0424 //=========================================================================== 0425 0426 ////////////////////////////////////////////////////////////////////////////// 0427 /// \brief A semantic type used for distinguishing failure values in an 0428 /// API that returns result types 0429 /// 0430 /// \tparam E the error type 0431 ////////////////////////////////////////////////////////////////////////////// 0432 template<typename E> 0433 class failure { 0434 static_assert(!is_result<typename std::decay<E>::type>::value, 0435 "A (possibly CV-qualified) result 'E' type is ill-formed."); 0436 static_assert(!is_failure<typename std::decay<E>::type>::value, 0437 "A (possibly CV-qualified) failure 'E' type is ill-formed."); 0438 static_assert(!std::is_void<typename std::decay<E>::type>::value, 0439 "A (possibly CV-qualified) 'void' 'E' type is ill-formed."); 0440 static_assert(!std::is_rvalue_reference<E>::value, 0441 "rvalue references for 'E' type is ill-formed. " 0442 "Only lvalue references are valid."); 0443 0444 //------------------------------------------------------------------------- 0445 // Public Member Types 0446 //------------------------------------------------------------------------- 0447 public: 0448 using error_type = E; 0449 0450 //------------------------------------------------------------------------- 0451 // Constructors / Assignment 0452 //------------------------------------------------------------------------- 0453 public: 0454 /// \brief Constructs a failure via default construction 0455 failure() = default; 0456 0457 /// \brief Constructs a failure by delegating construction to the 0458 /// underlying constructor 0459 /// 0460 /// \param args the arguments to forward to E's constructor 0461 template<typename... Args, typename = typename std::enable_if<std::is_constructible<E, Args...>::value>::type> 0462 constexpr failure(in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 0463 0464 /// \brief Constructs a failure by delegating construction to the 0465 /// underlying constructor 0466 /// 0467 /// \param ilist the initializer list 0468 /// \param args the arguments to forward to E's constructor 0469 template< 0470 typename U, 0471 typename... Args, 0472 typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>, Args...>::value>::type> 0473 constexpr failure(in_place_t, std::initializer_list<U> ilist, Args&&...args) noexcept( 0474 std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value); 0475 0476 /// \{ 0477 /// \brief Constructs a failure from the given error 0478 /// 0479 /// \param error the error to create a failure from 0480 template<typename E2, 0481 typename std::enable_if<detail::failure_is_implicit_value_convertible<E, E2>::value, int>::type = 0> 0482 constexpr failure(E2&& error) noexcept(std::is_nothrow_constructible<E, E2>::value); 0483 template<typename E2, 0484 typename std::enable_if<detail::failure_is_explicit_value_convertible<E, E2>::value, int>::type = 0> 0485 constexpr explicit failure(E2&& error) noexcept(std::is_nothrow_constructible<E, E2>::value); 0486 /// \} 0487 0488 /// \brief Constructs this failure by copying the contents of an existing 0489 /// one 0490 /// 0491 /// \param other the other failure to copy 0492 /* implicit */ failure(const failure& other) = default; 0493 0494 /// \brief Constructs this failure by moving the contents of an existing 0495 /// one 0496 /// 0497 /// \param other the other failure to move 0498 /* implicit */ failure(failure&& other) = default; 0499 0500 /// \brief Constructs this failure by copy-converting \p other 0501 /// 0502 /// \param other the other failure to copy 0503 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, const E2&>::value>::type> 0504 constexpr /* implicit */ failure(const failure<E2>& other) noexcept( 0505 std::is_nothrow_constructible<E, const E2&>::value); 0506 0507 /// \brief Constructs this failure by move-converting \p other 0508 /// 0509 /// \param other the other failure to copy 0510 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2&&>::value>::type> 0511 constexpr /* implicit */ failure(failure<E2>&& other) noexcept(std::is_nothrow_constructible<E, E2&&>::value); 0512 0513 //-------------------------------------------------------------------------- 0514 0515 /// \brief Assigns the value of \p error to this failure through 0516 /// move-assignment 0517 /// 0518 /// \param error the value to assign 0519 /// \return reference to `(*this)` 0520 template<typename E2, typename = typename std::enable_if<detail::failure_is_value_assignable<E, E2>::value>::type> 0521 RESULT_CPP14_CONSTEXPR auto operator=(E2&& error) noexcept(std::is_nothrow_assignable<E, E2>::value 0522 || std::is_lvalue_reference<E>::value) -> failure&; 0523 0524 /// \brief Assigns the contents of \p other to this by copy-assignment 0525 /// 0526 /// \param other the other failure to copy 0527 /// \return reference to `(*this)` 0528 auto operator=(const failure& other) -> failure& = default; 0529 0530 /// \brief Assigns the contents of \p other to this by move-assignment 0531 /// 0532 /// \param other the other failure to move 0533 /// \return reference to `(*this)` 0534 auto operator=(failure&& other) -> failure& = default; 0535 0536 /// \brief Assigns the contents of \p other to this by copy conversion 0537 /// 0538 /// \param other the other failure to copy-convert 0539 /// \return reference to `(*this)` 0540 template<typename E2, typename = typename std::enable_if<std::is_assignable<E&, const E2&>::value>::type> 0541 RESULT_CPP14_CONSTEXPR auto 0542 operator=(const failure<E2>& other) noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> failure&; 0543 0544 /// \brief Assigns the contents of \p other to this by move conversion 0545 /// 0546 /// \param other the other failure to move-convert 0547 /// \return reference to `(*this)` 0548 template<typename E2, typename = typename std::enable_if<std::is_assignable<E&, E2&&>::value>::type> 0549 RESULT_CPP14_CONSTEXPR auto operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) 0550 -> failure&; 0551 0552 //-------------------------------------------------------------------------- 0553 // Observers 0554 //-------------------------------------------------------------------------- 0555 public: 0556 /// \{ 0557 /// \brief Gets the underlying error 0558 /// 0559 /// \return the underlying error 0560 RESULT_CPP14_CONSTEXPR 0561 auto error() & noexcept -> typename std::add_lvalue_reference<E>::type; 0562 RESULT_CPP14_CONSTEXPR 0563 auto error() && noexcept -> typename std::add_rvalue_reference<E>::type; 0564 constexpr auto error() const& noexcept -> 0565 typename std::add_lvalue_reference<typename std::add_const<E>::type>::type; 0566 constexpr auto error() const&& noexcept -> 0567 typename std::add_rvalue_reference<typename std::add_const<E>::type>::type; 0568 /// \} 0569 0570 //------------------------------------------------------------------------- 0571 // Private Member Types 0572 //------------------------------------------------------------------------- 0573 private: 0574 using underlying_type = detail::wrapped_result_type<E>; 0575 0576 //------------------------------------------------------------------------- 0577 // Private Members 0578 //------------------------------------------------------------------------- 0579 private: 0580 underlying_type m_failure; 0581 }; 0582 0583 #if __cplusplus >= 201703L 0584 template<typename T> 0585 failure(std::reference_wrapper<T>) -> failure<T&>; 0586 0587 template<typename T> 0588 failure(T&&) -> failure<typename std::decay<T>::type>; 0589 #endif 0590 0591 //=========================================================================== 0592 // non-member functions : class : failure 0593 //=========================================================================== 0594 0595 //--------------------------------------------------------------------------- 0596 // Comparison 0597 //--------------------------------------------------------------------------- 0598 0599 template<typename E1, typename E2> 0600 constexpr auto operator==(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0601 template<typename E1, typename E2> 0602 constexpr auto operator!=(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0603 template<typename E1, typename E2> 0604 constexpr auto operator<(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0605 template<typename E1, typename E2> 0606 constexpr auto operator>(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0607 template<typename E1, typename E2> 0608 constexpr auto operator<=(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0609 template<typename E1, typename E2> 0610 constexpr auto operator>=(const failure<E1>& lhs, const failure<E2>& rhs) noexcept -> bool; 0611 0612 //--------------------------------------------------------------------------- 0613 // Utilities 0614 //--------------------------------------------------------------------------- 0615 0616 /// \brief Deduces and constructs a failure type from \p e 0617 /// 0618 /// \param e the failure value 0619 /// \return a constructed failure value 0620 template<typename E> 0621 RESULT_WARN_UNUSED constexpr auto 0622 fail(E&& e) noexcept(std::is_nothrow_constructible<typename std::decay<E>::type, E>::value) 0623 -> failure<typename std::decay<E>::type>; 0624 0625 /// \brief Deduces a failure reference from a reverence_wrapper 0626 /// 0627 /// \param e the failure value 0628 /// \return a constructed failure reference 0629 template<typename E> 0630 RESULT_WARN_UNUSED constexpr auto fail(std::reference_wrapper<E> e) noexcept -> failure<E&>; 0631 0632 /// \brief Constructs a failure type from a series of arguments 0633 /// 0634 /// \tparam E the failure type 0635 /// \param args the arguments to forward to E's constructor 0636 /// \return a constructed failure type 0637 template<typename E, 0638 typename... Args, 0639 typename = typename std::enable_if<std::is_constructible<E, Args...>::value>::type> 0640 RESULT_WARN_UNUSED constexpr auto fail(Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value) 0641 -> failure<E>; 0642 0643 /// \brief Constructs a failure type from an initializer list and series of 0644 /// arguments 0645 /// 0646 /// \tparam E the failure type 0647 /// \param args the arguments to forward to E's constructor 0648 /// \return a constructed failure type 0649 template<typename E, 0650 typename U, 0651 typename... Args, 0652 typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>, Args...>::value>::type> 0653 RESULT_WARN_UNUSED constexpr auto 0654 fail(std::initializer_list<U> ilist, 0655 Args&&...args) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value) -> failure<E>; 0656 0657 /// \brief Swaps the contents of two failure values 0658 /// 0659 /// \param lhs the left failure 0660 /// \param rhs the right failure 0661 template<typename E> 0662 auto swap(failure<E>& lhs, failure<E>& rhs) 0663 #if __cplusplus >= 201703L 0664 noexcept(std::is_nothrow_swappable<E>::value) -> void; 0665 #else 0666 noexcept(std::is_nothrow_move_constructible<E>::value) -> void; 0667 #endif 0668 0669 namespace detail { 0670 0671 //========================================================================= 0672 // class : unit 0673 //========================================================================= 0674 0675 /// \brief A standalone monostate object (effectively std::monostate). This 0676 /// exists to allow for `void` specializations 0677 struct unit { 0678 }; 0679 0680 //========================================================================= 0681 // non-member functions : class : unit 0682 //========================================================================= 0683 0684 constexpr auto operator==(unit, unit) noexcept -> bool 0685 { 0686 return true; 0687 } 0688 constexpr auto operator!=(unit, unit) noexcept -> bool 0689 { 0690 return false; 0691 } 0692 constexpr auto operator<(unit, unit) noexcept -> bool 0693 { 0694 return false; 0695 } 0696 constexpr auto operator>(unit, unit) noexcept -> bool 0697 { 0698 return false; 0699 } 0700 constexpr auto operator<=(unit, unit) noexcept -> bool 0701 { 0702 return true; 0703 } 0704 constexpr auto operator>=(unit, unit) noexcept -> bool 0705 { 0706 return true; 0707 } 0708 0709 //========================================================================= 0710 // class : detail::result_union<T, E, IsTrivial> 0711 //========================================================================= 0712 0713 /////////////////////////////////////////////////////////////////////////// 0714 /// \brief A basic utility that acts as a union containing the T and E 0715 /// types 0716 /// 0717 /// This is specialized on the case that both T and E are trivial, in which 0718 /// case `result_union` is also trivial 0719 /// 0720 /// \tparam T the value type result to be returned 0721 /// \tparam E the error type returned on failure 0722 /// \tparam IsTrivial Whether or not both T and E are trivial 0723 /////////////////////////////////////////////////////////////////////////// 0724 template<typename T, 0725 typename E, 0726 bool IsTrivial = std::is_trivially_destructible<T>::value&& std::is_trivially_destructible<E>::value> 0727 struct result_union { 0728 //----------------------------------------------------------------------- 0729 // Public Member Types 0730 //----------------------------------------------------------------------- 0731 0732 using underlying_value_type = wrapped_result_type<T>; 0733 using underlying_error_type = E; 0734 0735 //----------------------------------------------------------------------- 0736 // Constructors / Assignment 0737 //----------------------------------------------------------------------- 0738 0739 /// \brief Constructs an empty object 0740 /// 0741 /// This is for use with conversion constructors, since it allows a 0742 /// temporary unused object to be set 0743 result_union(unit) noexcept; 0744 0745 /// \brief Constructs the underlying value from the specified \p args 0746 /// 0747 /// \param args the arguments to forward to T's constructor 0748 template<typename... Args> 0749 constexpr result_union(in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value); 0750 0751 /// \brief Constructs the underlying error from the specified \p args 0752 /// 0753 /// \param args the arguments to forward to E's constructor 0754 template<typename... Args> 0755 constexpr result_union(in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 0756 0757 result_union(const result_union&) = default; 0758 result_union(result_union&&) = default; 0759 0760 //----------------------------------------------------------------------- 0761 0762 auto operator=(const result_union&) -> result_union& = default; 0763 auto operator=(result_union&&) -> result_union& = default; 0764 0765 //----------------------------------------------------------------------- 0766 // Modifiers 0767 //----------------------------------------------------------------------- 0768 0769 /// \brief A no-op for trivial types 0770 auto destroy() const noexcept -> void; 0771 0772 //----------------------------------------------------------------------- 0773 // Public Members 0774 //----------------------------------------------------------------------- 0775 0776 union { 0777 underlying_value_type m_value; 0778 underlying_error_type m_error; 0779 unit m_empty; 0780 }; 0781 bool m_has_value; 0782 }; 0783 0784 //------------------------------------------------------------------------- 0785 0786 template<typename T, typename E> 0787 struct result_union<T, E, false> { 0788 //----------------------------------------------------------------------- 0789 // Public Member Types 0790 //----------------------------------------------------------------------- 0791 0792 using underlying_value_type = wrapped_result_type<T>; 0793 using underlying_error_type = E; 0794 0795 //----------------------------------------------------------------------- 0796 // Constructors / Assignment / Destructor 0797 //----------------------------------------------------------------------- 0798 0799 /// \brief Constructs an empty object 0800 /// 0801 /// This is for use with conversion constructors, since it allows a 0802 /// temporary unused object to be set 0803 result_union(unit) noexcept; 0804 0805 /// \brief Constructs the underlying value from the specified \p args 0806 /// 0807 /// \param args the arguments to forward to T's constructor 0808 template<typename... Args> 0809 constexpr result_union(in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value); 0810 0811 /// \brief Constructs the underlying error from the specified \p args 0812 /// 0813 /// \param args the arguments to forward to E's constructor 0814 template<typename... Args> 0815 constexpr result_union(in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 0816 0817 result_union(const result_union&) = default; 0818 result_union(result_union&&) = default; 0819 0820 //----------------------------------------------------------------------- 0821 0822 /// \brief Destroys the underlying stored object 0823 ~result_union() noexcept(std::is_nothrow_destructible<T>::value&& std::is_nothrow_destructible<E>::value); 0824 0825 //----------------------------------------------------------------------- 0826 0827 auto operator=(const result_union&) -> result_union& = default; 0828 auto operator=(result_union&&) -> result_union& = default; 0829 0830 //----------------------------------------------------------------------- 0831 // Modifiers 0832 //----------------------------------------------------------------------- 0833 0834 /// \brief Destroys the underlying stored object 0835 auto destroy() -> void; 0836 0837 //----------------------------------------------------------------------- 0838 // Public Members 0839 //----------------------------------------------------------------------- 0840 0841 union { 0842 underlying_value_type m_value; 0843 underlying_error_type m_error; 0844 unit m_empty; 0845 }; 0846 bool m_has_value; 0847 }; 0848 0849 //========================================================================= 0850 // class : result_construct_base<T, E> 0851 //========================================================================= 0852 0853 /////////////////////////////////////////////////////////////////////////// 0854 /// \brief Base class of assignment to enable construction and assignment 0855 /// 0856 /// This class is used with several pieces of construction to ensure 0857 /// trivial constructibility and assignability: 0858 /// 0859 /// * `result_trivial_copy_ctor_base` 0860 /// * `result_trivial_move_ctor_base` 0861 /// * `result_copy_assign_base` 0862 /// * `result_move_assign_base` 0863 /// 0864 /// \tparam T the value type 0865 /// \tparam E the error type 0866 /////////////////////////////////////////////////////////////////////////// 0867 template<typename T, typename E> 0868 struct result_construct_base { 0869 //----------------------------------------------------------------------- 0870 // Constructors / Assignment 0871 //----------------------------------------------------------------------- 0872 0873 /// \brief Constructs an empty object 0874 /// 0875 /// This is for use with conversion constructors, since it allows a 0876 /// temporary unused object to be set 0877 result_construct_base(unit) noexcept; 0878 0879 /// \brief Constructs the underlying value from the specified \p args 0880 /// 0881 /// \param args the arguments to forward to T's constructor 0882 template<typename... Args> 0883 constexpr result_construct_base(in_place_t, 0884 Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value); 0885 0886 /// \brief Constructs the underlying error from the specified \p args 0887 /// 0888 /// \param args the arguments to forward to E's constructor 0889 template<typename... Args> 0890 constexpr result_construct_base(in_place_error_t, 0891 Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 0892 0893 result_construct_base(const result_construct_base&) = default; 0894 result_construct_base(result_construct_base&&) = default; 0895 0896 auto operator=(const result_construct_base&) -> result_construct_base& = default; 0897 auto operator=(result_construct_base&&) -> result_construct_base& = default; 0898 0899 //----------------------------------------------------------------------- 0900 // Construction / Assignment 0901 //----------------------------------------------------------------------- 0902 0903 /// \brief Constructs the value type from \p args 0904 /// 0905 /// \note This is an implementation detail only meant to be used during 0906 /// construction 0907 /// 0908 /// \pre there is no contained value or error at the time of construction 0909 /// 0910 /// \param args the arguments to forward to T's constructor 0911 template<typename... Args> 0912 auto construct_value(Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> void; 0913 0914 /// \brief Constructs the error type from \p args 0915 /// 0916 /// \note This is an implementation detail only meant to be used during 0917 /// construction 0918 /// 0919 /// \pre there is no contained value or error at the time of construction 0920 /// 0921 /// \param args the arguments to forward to E's constructor 0922 template<typename... Args> 0923 auto construct_error(Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value) -> void; 0924 0925 /// \brief Constructs the underlying error from the \p other result 0926 /// 0927 /// If \p other contains a value, then the T type will be 0928 /// default-constructed. 0929 /// 0930 /// \note This is an implementation detail only meant to be used during 0931 /// construction of `result<void, E>` types 0932 /// 0933 /// \pre there is no contained value or error at the time of construction 0934 /// 0935 /// \param other the other result to construct 0936 template<typename Result> 0937 auto construct_error_from_result(Result&& other) -> void; 0938 0939 /// \brief Constructs the underlying type from a result object 0940 /// 0941 /// \note This is an implementation detail only meant to be used during 0942 /// construction 0943 /// 0944 /// \pre there is no contained value or error at the time of construction 0945 /// 0946 /// \param other the other result to construct 0947 template<typename Result> 0948 auto construct_from_result(Result&& other) -> void; 0949 0950 //----------------------------------------------------------------------- 0951 0952 template<typename Value> 0953 auto assign_value(Value&& value) noexcept(std::is_nothrow_assignable<T, Value>::value) -> void; 0954 0955 template<typename Error> 0956 auto assign_error(Error&& error) noexcept(std::is_nothrow_assignable<E, Error>::value) -> void; 0957 0958 template<typename Result> 0959 auto assign_from_result(Result&& other) -> void; 0960 0961 //----------------------------------------------------------------------- 0962 0963 template<typename ReferenceWrapper> 0964 auto construct_value_from_result_impl(std::true_type, ReferenceWrapper&& reference) noexcept -> void; 0965 0966 template<typename Value> 0967 auto construct_value_from_result_impl(std::false_type, 0968 Value&& value) noexcept(std::is_nothrow_constructible<T, Value>::value) 0969 -> void; 0970 0971 template<typename Result> 0972 auto assign_value_from_result_impl(std::true_type, Result&& other) -> void; 0973 0974 template<typename Result> 0975 auto assign_value_from_result_impl(std::false_type, Result&& other) -> void; 0976 0977 //----------------------------------------------------------------------- 0978 // Public Members 0979 //----------------------------------------------------------------------- 0980 0981 using storage_type = result_union<T, E>; 0982 0983 storage_type storage; 0984 }; 0985 0986 //========================================================================= 0987 // class : result_trivial_copy_ctor_base 0988 //========================================================================= 0989 0990 template<typename T, typename E> 0991 struct result_trivial_copy_ctor_base_impl : result_construct_base<T, E> { 0992 using base_type = result_construct_base<T, E>; 0993 using base_type::base_type; 0994 0995 result_trivial_copy_ctor_base_impl(const result_trivial_copy_ctor_base_impl& other) noexcept( 0996 std::is_nothrow_copy_constructible<T>::value&& std::is_nothrow_copy_constructible<E>::value); 0997 result_trivial_copy_ctor_base_impl(result_trivial_copy_ctor_base_impl&& other) = default; 0998 0999 auto operator=(const result_trivial_copy_ctor_base_impl& other) -> result_trivial_copy_ctor_base_impl& = default; 1000 auto operator=(result_trivial_copy_ctor_base_impl&& other) -> result_trivial_copy_ctor_base_impl& = default; 1001 }; 1002 1003 template<bool Condition, typename Base> 1004 using conditionally_nest_type = typename std::conditional<Condition, typename Base::base_type, Base>::type; 1005 1006 template<typename T, typename E> 1007 using result_trivial_copy_ctor_base = conditionally_nest_type<std::is_trivially_copy_constructible<T>::value 1008 && std::is_trivially_copy_constructible<E>::value, 1009 result_trivial_copy_ctor_base_impl<T, E>>; 1010 1011 //========================================================================= 1012 // class : result_trivial_move_ctor_base 1013 //========================================================================= 1014 1015 template<typename T, typename E> 1016 struct result_trivial_move_ctor_base_impl : result_trivial_copy_ctor_base<T, E> { 1017 using base_type = result_trivial_copy_ctor_base<T, E>; 1018 using base_type::base_type; 1019 1020 result_trivial_move_ctor_base_impl(const result_trivial_move_ctor_base_impl& other) = default; 1021 result_trivial_move_ctor_base_impl(result_trivial_move_ctor_base_impl&& other) noexcept( 1022 std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_constructible<E>::value); 1023 1024 auto operator=(const result_trivial_move_ctor_base_impl& other) -> result_trivial_move_ctor_base_impl& = default; 1025 auto operator=(result_trivial_move_ctor_base_impl&& other) -> result_trivial_move_ctor_base_impl& = default; 1026 }; 1027 1028 template<typename T, typename E> 1029 using result_trivial_move_ctor_base = conditionally_nest_type<std::is_trivially_move_constructible<T>::value 1030 && std::is_trivially_move_constructible<E>::value, 1031 result_trivial_move_ctor_base_impl<T, E>>; 1032 1033 //========================================================================= 1034 // class : result_trivial_copy_assign_base 1035 //========================================================================= 1036 1037 template<typename T, typename E> 1038 struct result_trivial_copy_assign_base_impl : result_trivial_move_ctor_base<T, E> { 1039 using base_type = result_trivial_move_ctor_base<T, E>; 1040 using base_type::base_type; 1041 1042 result_trivial_copy_assign_base_impl(const result_trivial_copy_assign_base_impl& other) = default; 1043 result_trivial_copy_assign_base_impl(result_trivial_copy_assign_base_impl&& other) = default; 1044 1045 auto operator=(const result_trivial_copy_assign_base_impl& other) noexcept( 1046 std::is_nothrow_copy_constructible<T>::value&& std::is_nothrow_copy_constructible<E>::value&& 1047 std::is_nothrow_copy_assignable<T>::value&& std::is_nothrow_copy_assignable<E>::value) 1048 -> result_trivial_copy_assign_base_impl&; 1049 auto operator=(result_trivial_copy_assign_base_impl&& other) -> result_trivial_copy_assign_base_impl& = default; 1050 }; 1051 1052 template<typename T, typename E> 1053 using result_trivial_copy_assign_base = conditionally_nest_type< 1054 std::is_trivially_copy_constructible<T>::value && std::is_trivially_copy_constructible<E>::value 1055 && std::is_trivially_copy_assignable<T>::value && std::is_trivially_copy_assignable<E>::value 1056 && std::is_trivially_destructible<T>::value && std::is_trivially_destructible<E>::value, 1057 result_trivial_copy_assign_base_impl<T, E>>; 1058 1059 //========================================================================= 1060 // class : result_trivial_move_assign_base 1061 //========================================================================= 1062 1063 template<typename T, typename E> 1064 struct result_trivial_move_assign_base_impl : result_trivial_copy_assign_base<T, E> { 1065 using base_type = result_trivial_copy_assign_base<T, E>; 1066 using base_type::base_type; 1067 1068 result_trivial_move_assign_base_impl(const result_trivial_move_assign_base_impl& other) = default; 1069 result_trivial_move_assign_base_impl(result_trivial_move_assign_base_impl&& other) = default; 1070 1071 auto operator=(const result_trivial_move_assign_base_impl& other) 1072 -> result_trivial_move_assign_base_impl& = default; 1073 auto operator=(result_trivial_move_assign_base_impl&& other) noexcept( 1074 std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_constructible<E>::value&& 1075 std::is_nothrow_move_assignable<T>::value&& std::is_nothrow_move_assignable<E>::value) 1076 -> result_trivial_move_assign_base_impl&; 1077 }; 1078 1079 template<typename T, typename E> 1080 using result_trivial_move_assign_base = conditionally_nest_type< 1081 std::is_trivially_move_constructible<T>::value && std::is_trivially_move_constructible<E>::value 1082 && std::is_trivially_move_assignable<T>::value && std::is_trivially_move_assignable<E>::value 1083 && std::is_trivially_destructible<T>::value && std::is_trivially_destructible<E>::value, 1084 result_trivial_move_assign_base_impl<T, E>>; 1085 1086 //========================================================================= 1087 // class : disable_copy_ctor 1088 //========================================================================= 1089 1090 template<typename T, typename E> 1091 struct disable_copy_ctor : result_trivial_move_assign_base<T, E> { 1092 using base_type = result_trivial_move_assign_base<T, E>; 1093 using base_type::base_type; 1094 1095 disable_copy_ctor(const disable_copy_ctor& other) = delete; 1096 disable_copy_ctor(disable_copy_ctor&& other) = default; 1097 1098 auto operator=(const disable_copy_ctor& other) -> disable_copy_ctor& = default; 1099 auto operator=(disable_copy_ctor&& other) -> disable_copy_ctor& = default; 1100 }; 1101 1102 template<typename T, typename E> 1103 using result_copy_ctor_base = 1104 conditionally_nest_type<std::is_copy_constructible<T>::value && std::is_copy_constructible<E>::value, 1105 disable_copy_ctor<T, E>>; 1106 1107 //========================================================================= 1108 // class : disable_move_ctor 1109 //========================================================================= 1110 1111 template<typename T, typename E> 1112 struct disable_move_ctor : result_copy_ctor_base<T, E> { 1113 using base_type = result_copy_ctor_base<T, E>; 1114 using base_type::base_type; 1115 1116 disable_move_ctor(const disable_move_ctor& other) = default; 1117 disable_move_ctor(disable_move_ctor&& other) = delete; 1118 1119 auto operator=(const disable_move_ctor& other) -> disable_move_ctor& = default; 1120 auto operator=(disable_move_ctor&& other) -> disable_move_ctor& = default; 1121 }; 1122 1123 template<typename T, typename E> 1124 using result_move_ctor_base = 1125 conditionally_nest_type<std::is_move_constructible<T>::value && std::is_move_constructible<E>::value, 1126 disable_move_ctor<T, E>>; 1127 1128 //========================================================================= 1129 // class : disable_move_assignment 1130 //========================================================================= 1131 1132 template<typename T, typename E> 1133 struct disable_move_assignment : result_move_ctor_base<T, E> { 1134 using base_type = result_move_ctor_base<T, E>; 1135 using base_type::base_type; 1136 1137 disable_move_assignment(const disable_move_assignment& other) = default; 1138 disable_move_assignment(disable_move_assignment&& other) = default; 1139 1140 auto operator=(const disable_move_assignment& other) -> disable_move_assignment& = delete; 1141 auto operator=(disable_move_assignment&& other) -> disable_move_assignment& = default; 1142 }; 1143 1144 template<typename T, typename E> 1145 using result_copy_assign_base = 1146 conditionally_nest_type<std::is_nothrow_copy_constructible<T>::value && std::is_nothrow_copy_constructible<E>::value 1147 && std::is_copy_assignable<wrapped_result_type<T>>::value 1148 && std::is_copy_assignable<E>::value, 1149 disable_move_assignment<T, E>>; 1150 1151 //========================================================================= 1152 // class : disable_copy_assignment 1153 //========================================================================= 1154 1155 template<typename T, typename E> 1156 struct disable_copy_assignment : result_copy_assign_base<T, E> { 1157 using base_type = result_copy_assign_base<T, E>; 1158 using base_type::base_type; 1159 1160 disable_copy_assignment(const disable_copy_assignment& other) = default; 1161 disable_copy_assignment(disable_copy_assignment&& other) = default; 1162 1163 auto operator=(const disable_copy_assignment& other) -> disable_copy_assignment& = default; 1164 auto operator=(disable_copy_assignment&& other) -> disable_copy_assignment& = delete; 1165 }; 1166 1167 template<typename T, typename E> 1168 using result_move_assign_base = 1169 conditionally_nest_type<std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_constructible<E>::value 1170 && std::is_move_assignable<wrapped_result_type<T>>::value 1171 && std::is_move_assignable<E>::value, 1172 disable_copy_assignment<T, E>>; 1173 1174 //========================================================================= 1175 // alias : result_storage 1176 //========================================================================= 1177 1178 template<typename T, typename E> 1179 using result_storage = result_move_assign_base<T, E>; 1180 1181 //========================================================================= 1182 // traits : result 1183 //========================================================================= 1184 1185 template<typename T1, typename E1, typename T2, typename E2> 1186 using result_is_convertible = std::integral_constant< 1187 bool, 1188 ( 1189 // T1 constructible from result<T2,E2> 1190 std::is_constructible<T1, result<T2, E2>&>::value || std::is_constructible<T1, const result<T2, E2>&>::value 1191 || std::is_constructible<T1, result<T2, E2>&&>::value 1192 || std::is_constructible<T1, const result<T2, E2>&&>::value || 1193 1194 // E1 constructible from result<T2,E2> 1195 std::is_constructible<E1, result<T2, E2>&>::value || std::is_constructible<E1, const result<T2, E2>&>::value 1196 || std::is_constructible<E1, result<T2, E2>&&>::value 1197 || std::is_constructible<E1, const result<T2, E2>&&>::value || 1198 1199 // result<T2,E2> convertible to T1 1200 std::is_convertible<result<T2, E2>&, T1>::value || std::is_convertible<const result<T2, E2>&, T1>::value 1201 || std::is_convertible<result<T2, E2>&&, T1>::value || std::is_convertible<const result<T2, E2>&&, T1>::value || 1202 1203 // result<T2,E2> convertible to E2 1204 std::is_convertible<result<T2, E2>&, E1>::value || std::is_convertible<const result<T2, E2>&, E1>::value 1205 || std::is_convertible<result<T2, E2>&&, E1>::value || std::is_convertible<const result<T2, E2>&&, E1>::value)>; 1206 1207 //------------------------------------------------------------------------- 1208 1209 template<typename T1, typename E1, typename T2, typename E2> 1210 using result_is_copy_convertible = 1211 std::integral_constant<bool, 1212 (!result_is_convertible<T1, E1, T2, E2>::value && std::is_constructible<T1, const T2&>::value 1213 && std::is_constructible<E1, const E2&>::value)>; 1214 1215 template<typename T1, typename E1, typename T2, typename E2> 1216 using result_is_implicit_copy_convertible = 1217 std::integral_constant<bool, 1218 (result_is_copy_convertible<T1, E1, T2, E2>::value 1219 && std::is_convertible<const T2&, T1>::value && std::is_convertible<const E2&, E1>::value)>; 1220 1221 template<typename T1, typename E1, typename T2, typename E2> 1222 using result_is_explicit_copy_convertible = 1223 std::integral_constant<bool, 1224 (result_is_copy_convertible<T1, E1, T2, E2>::value 1225 && (!std::is_convertible<const T2&, T1>::value 1226 || !std::is_convertible<const E2&, E1>::value))>; 1227 1228 //------------------------------------------------------------------------- 1229 1230 template<typename T1, typename E1, typename T2, typename E2> 1231 using result_is_move_convertible = 1232 std::integral_constant<bool, 1233 (!result_is_convertible<T1, E1, T2, E2>::value && std::is_constructible<T1, T2&&>::value 1234 && std::is_constructible<E1, E2&&>::value)>; 1235 1236 template<typename T1, typename E1, typename T2, typename E2> 1237 using result_is_implicit_move_convertible = 1238 std::integral_constant<bool, 1239 (result_is_move_convertible<T1, E1, T2, E2>::value && std::is_convertible<T2&&, T1>::value 1240 && std::is_convertible<E2&&, E1>::value)>; 1241 1242 template<typename T1, typename E1, typename T2, typename E2> 1243 using result_is_explicit_move_convertible = 1244 std::integral_constant<bool, 1245 (result_is_move_convertible<T1, E1, T2, E2>::value 1246 && (!std::is_convertible<T2&&, T1>::value || !std::is_convertible<E2&&, E1>::value))>; 1247 1248 //------------------------------------------------------------------------- 1249 1250 template<typename T, typename U> 1251 using result_is_value_convertible = 1252 std::integral_constant<bool, 1253 (std::is_constructible<T, U&&>::value 1254 && !std::is_same<typename std::decay<U>::type, in_place_t>::value 1255 && !std::is_same<typename std::decay<U>::type, in_place_error_t>::value 1256 && !is_result<typename std::decay<U>::type>::value)>; 1257 1258 template<typename T, typename U> 1259 using result_is_explicit_value_convertible = 1260 std::integral_constant<bool, (result_is_value_convertible<T, U>::value && !std::is_convertible<U&&, T>::value)>; 1261 1262 template<typename T, typename U> 1263 using result_is_implicit_value_convertible = 1264 std::integral_constant<bool, (result_is_value_convertible<T, U>::value && std::is_convertible<U&&, T>::value)>; 1265 1266 //------------------------------------------------------------------------- 1267 1268 template<typename T1, typename E1, typename T2, typename E2> 1269 using result_is_convert_assignable = std::integral_constant< 1270 bool, 1271 (result_is_convertible<T1, E1, T2, E2>::value && 1272 1273 std::is_assignable<T1&, result<T2, E2>&>::value && std::is_assignable<T1&, const result<T2, E2>&>::value 1274 && std::is_assignable<T1&, result<T2, E2>&&>::value && std::is_assignable<T1&, const result<T2, E2>&&>::value && 1275 1276 std::is_assignable<E1&, result<T2, E2>&>::value && std::is_assignable<E1&, const result<T2, E2>&>::value 1277 && std::is_assignable<E1&, result<T2, E2>&&>::value && std::is_assignable<E1&, const result<T2, E2>&&>::value)>; 1278 1279 template<typename T1, typename E1, typename T2, typename E2> 1280 using result_is_copy_convert_assignable = 1281 std::integral_constant<bool, 1282 (!result_is_convert_assignable<T1, E1, T2, E2>::value && 1283 1284 std::is_nothrow_constructible<T1, const T2&>::value 1285 && std::is_assignable<wrapped_result_type<T1>&, const T2&>::value 1286 && std::is_nothrow_constructible<E1, const E2&>::value 1287 && std::is_assignable<E1&, const E2&>::value)>; 1288 1289 template<typename T1, typename E1, typename T2, typename E2> 1290 using result_is_move_convert_assignable = 1291 std::integral_constant<bool, 1292 (!result_is_convert_assignable<T1, E1, T2, E2>::value && 1293 1294 std::is_nothrow_constructible<T1, T2&&>::value && std::is_assignable<T1&, T2&&>::value 1295 && std::is_nothrow_constructible<E1, E2&&>::value && std::is_assignable<E1&, E2&&>::value)>; 1296 1297 //------------------------------------------------------------------------- 1298 1299 template<typename T, typename U> 1300 using result_is_value_assignable = std::integral_constant< 1301 bool, 1302 (!is_result<typename std::decay<U>::type>::value && !is_failure<typename std::decay<U>::type>::value 1303 && std::is_nothrow_constructible<T, U>::value && std::is_assignable<wrapped_result_type<T>&, U>::value 1304 && (!std::is_same<typename std::decay<U>::type, typename std::decay<T>::type>::value 1305 || !std::is_scalar<T>::value))>; 1306 1307 template<typename E, typename E2> 1308 using result_is_failure_assignable = 1309 std::integral_constant<bool, (std::is_nothrow_constructible<E, E2>::value && std::is_assignable<E&, E2>::value)>; 1310 1311 // Friending 'extract_error" below was causing some compilers to incorrectly 1312 // identify `exp.m_storage.m_error` as being an access violation despite the 1313 // friendship. Using a type name instead seems to be ubiquitous across 1314 // compilers 1315 struct result_error_extractor { 1316 template<typename T, typename E> 1317 static constexpr auto get(const result<T, E>& exp) noexcept -> const E&; 1318 template<typename T, typename E> 1319 static constexpr auto get(result<T, E>& exp) noexcept -> E&; 1320 }; 1321 1322 template<typename T, typename E> 1323 constexpr auto extract_error(const result<T, E>& exp) noexcept -> const E&; 1324 1325 template<typename E> 1326 [[noreturn]] auto throw_bad_result_access(E&& error) -> void; 1327 1328 template<typename String, typename E> 1329 [[noreturn]] auto throw_bad_result_access_message(String&& message, E&& error) -> void; 1330 1331 } // namespace detail 1332 1333 ///////////////////////////////////////////////////////////////////////////// 1334 /// \brief The class template `result` manages result results from APIs, 1335 /// while encoding possible failure conditions. 1336 /// 1337 /// A common use-case for result is the return value of a function that 1338 /// may fail. As opposed to other approaches, such as `std::pair<T,bool>` 1339 /// or `std::optional`, `result` more accurately conveys the intent of the 1340 /// user along with the failure condition to the caller. This effectively 1341 /// produces an orthogonal error handling mechanism that allows for exception 1342 /// safety while also allowing discrete testability of the return type. 1343 /// 1344 /// `result<T,E>` types may contain a `T` value, which signifies that an 1345 /// operation succeeded in producing the result value of type `T`. If an 1346 /// `result` does not contain a `T` value, it will always contain an `E` 1347 /// error condition instead. 1348 /// 1349 /// An `result<T,E>` can always be queried for a possible error case by 1350 /// calling the `error()` function, even if it contains a value. 1351 /// In the case that a `result<T,E>` contains a value object, this will 1352 /// simply return an `E` object constructed through default aggregate 1353 /// construction, as if through the expression `E{}`, which is assumed to be 1354 /// a "valid" (no-error) state for an `E` type. 1355 /// For example: 1356 /// 1357 /// * `std::error_code{}` produces a default-construct error-code, which is 1358 /// the "no error" state, 1359 /// * integral (or enum) error codes produce a `0` value (no error), thanks to 1360 /// zero-initialization, 1361 /// * `std::exception_ptr{}` produces a null-pointer, 1362 /// * `std::string{}` produces an empty string `""`, 1363 /// * etc. 1364 /// 1365 /// When a `result<T,E>` contains either a value or error, the storage for 1366 /// that object is guaranteed to be allocated as part of the result 1367 /// object's footprint, i.e. no dynamic memory allocation ever takes place. 1368 /// Thus, a result object models an object, not a pointer, even though the 1369 /// `operator*()` and `operator->()` are defined. 1370 /// 1371 /// When an object of type `result<T,E>` is contextually converted to 1372 /// `bool`, the conversion returns `true` if the object contains a value and 1373 /// `false` if it contains an error. 1374 /// 1375 /// `result` objects do not have a "valueless" state like `variant`s do. 1376 /// Once a `result` has been constructed with a value or error, the 1377 /// active underlying type can only be changed through assignment which may 1378 /// is only enabled if construction is guaranteed to be *non-throwing*. This 1379 /// ensures that a valueless state cannot occur naturally. 1380 /// 1381 /// Example Use: 1382 /// \code 1383 /// auto to_string(int x) -> result<std::string> 1384 /// { 1385 /// try { 1386 /// return std::stoi(x); 1387 /// } catch (const std::invalid_argument&) { 1388 /// return fail(std::errc::invalid_argument); 1389 /// } catch (const std::std::out_of_range&) { 1390 /// return fail(std::errc::result_out_of_range); 1391 /// } 1392 /// } 1393 /// \endcode 1394 /// 1395 /// \note If using C++17 or above, `fail` can be replaced with 1396 /// `failure{...}` thanks to CTAD. 1397 /// 1398 /// \tparam T the underlying value type 1399 /// \tparam E the underlying error type 1400 /////////////////////////////////////////////////////////////////////////// 1401 template<typename T, typename E> 1402 class RESULT_NODISCARD result { 1403 // Type requirements 1404 1405 static_assert(!std::is_abstract<T>::value, "It is ill-formed for T to be abstract type"); 1406 static_assert(!std::is_same<typename std::decay<T>::type, in_place_t>::value, 1407 "It is ill-formed for T to be a (possibly CV-qualified) in_place_t type"); 1408 static_assert(!is_result<typename std::decay<T>::type>::value, 1409 "It is ill-formed for T to be a (possibly CV-qualified) 'result' type"); 1410 static_assert(!is_failure<typename std::decay<T>::type>::value, 1411 "It is ill-formed for T to be a (possibly CV-qualified) 'failure' type"); 1412 static_assert(!std::is_rvalue_reference<T>::value, 1413 "It is ill-formed for T to be an rvalue 'result type. " 1414 "Only lvalue references are valid."); 1415 1416 static_assert(!std::is_abstract<E>::value, "It is ill-formed for E to be abstract type"); 1417 static_assert(!std::is_void<typename std::decay<E>::type>::value, 1418 "It is ill-formed for E to be (possibly CV-qualified) void type"); 1419 static_assert(!is_result<typename std::decay<E>::type>::value, 1420 "It is ill-formed for E to be a (possibly CV-qualified) 'result' type"); 1421 static_assert(!is_failure<typename std::decay<E>::type>::value, 1422 "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type"); 1423 static_assert(!std::is_same<typename std::decay<E>::type, in_place_t>::value, 1424 "It is ill-formed for E to be a (possibly CV-qualified) in_place_t type"); 1425 static_assert(!std::is_reference<E>::value, 1426 "It is ill-formed for E to be a reference type. " 1427 "Only T types may be lvalue references"); 1428 1429 // Friendship 1430 1431 friend detail::result_error_extractor; 1432 1433 template<typename T2, typename E2> 1434 friend class result; 1435 1436 //------------------------------------------------------------------------- 1437 // Public Member Types 1438 //------------------------------------------------------------------------- 1439 public: 1440 using value_type = T; ///< The value type of this result 1441 using error_type = E; ///< The error type of this result 1442 using failure_type = failure<E>; ///< The failure type 1443 1444 template<typename U> 1445 using rebind = result<U, E>; ///< Rebinds the result type 1446 1447 //------------------------------------------------------------------------- 1448 // Constructor / Destructor / Assignment 1449 //------------------------------------------------------------------------- 1450 public: 1451 /// \brief Default-constructs a result with the underlying value type 1452 /// active 1453 /// 1454 /// This constructor is only enabled if `T` is default-constructible 1455 /// 1456 /// ### Examples 1457 /// 1458 /// Basic Usage: 1459 /// 1460 /// ```cpp 1461 /// assert(cpp::result<std::string,int>{} == std::string{}); 1462 /// ``` 1463 template<typename U = T, typename = typename std::enable_if<std::is_constructible<U>::value>::type> 1464 constexpr result() noexcept(std::is_nothrow_constructible<U>::value); 1465 1466 /// \brief Copy constructs this result 1467 /// 1468 /// If \p other contains a value, initializes the contained value as if 1469 /// direct-initializing (but not direct-list-initializing) an object of 1470 /// type `T` with the expression *other. 1471 /// 1472 /// If other contains an error, constructs an object that contains a copy 1473 /// of that error. 1474 /// 1475 /// \note This constructor is defined as deleted if 1476 /// `std::is_copy_constructible<T>::value` or 1477 /// `std::is_copy_constructible<E>::value` is `false` 1478 /// 1479 /// \note This constructor is defined as trivial if both 1480 /// `std::is_trivially_copy_constructible<T>::value` and 1481 /// `std::is_trivially_copy_constructible<E>::value` are `true` 1482 /// 1483 /// ### Examples 1484 /// 1485 /// Basic Usage: 1486 /// 1487 /// ```cpp 1488 /// const auto r = cpp::result<int,int>{42}; 1489 /// const auto s = r; 1490 /// 1491 /// assert(r == s); 1492 /// ``` 1493 /// 1494 /// \param other the result to copy 1495 constexpr result(const result& other) = default; 1496 1497 /// \brief Move constructs a result 1498 /// 1499 /// If other contains a value, initializes the contained value as if 1500 /// direct-initializing (but not direct-list-initializing) an object 1501 /// of type T with the expression `std::move(*other)` and does not make 1502 /// other empty: a moved-from result still contains a value, but the 1503 /// value itself is moved from. 1504 /// 1505 /// If other contains an error, move-constructs this result from that 1506 /// error. 1507 /// 1508 /// \note This constructor is defined as deleted if 1509 /// `std::is_move_constructible<T>::value` or 1510 /// `std::is_move_constructible<E>::value` is `false` 1511 /// 1512 /// \note This constructor is defined as trivial if both 1513 /// `std::is_trivially_move_constructible<T>::value` and 1514 /// `std::is_trivially_move_constructible<E>::value` are `true` 1515 /// 1516 /// ### Examples 1517 /// 1518 /// Basic Usage: 1519 /// 1520 /// ```cpp 1521 /// auto r = cpp::result<std::string,int>{"hello world"}; 1522 /// auto s = std::move(r); 1523 /// 1524 /// assert(s == "hello world"); 1525 /// ``` 1526 /// 1527 /// \param other the result to move 1528 constexpr result(result&& other) = default; 1529 1530 /// \{ 1531 /// \brief Converting copy constructor 1532 /// 1533 /// If \p other contains a value, constructs a result object 1534 /// that contains a value, initialized as if direct-initializing 1535 /// (but not direct-list-initializing) an object of type `T` with the 1536 /// expression `*other`. 1537 /// 1538 /// If \p other contains an error, constructs a result object that 1539 /// contains an error, initialized as if direct-initializing 1540 /// (but not direct-list-initializing) an object of type `E`. 1541 /// 1542 /// \note This constructor does not participate in overload resolution 1543 /// unless the following conditions are met: 1544 /// - `std::is_constructible_v<T, const U&>` is `true` 1545 /// - T is not constructible or convertible from any expression 1546 /// of type (possibly const) `result<T2,E2>` 1547 /// - E is not constructible or convertible from any expression 1548 /// of type (possible const) `result<T2,E2>` 1549 /// 1550 /// \note This constructor is explicit if and only if 1551 /// `std::is_convertible_v<const T2&, T>` or 1552 /// `std::is_convertible_v<const E2&, E>` is `false` 1553 /// 1554 /// ### Examples 1555 /// 1556 /// Basic Usage: 1557 /// 1558 /// ```cpp 1559 /// const auto r = cpp::result<int,int>{42}; 1560 /// const auto s = cpp::result<long,long>{r}; 1561 /// 1562 /// assert(r == s); 1563 /// ``` 1564 /// 1565 /// \param other the other type to convert 1566 template<typename T2, 1567 typename E2, 1568 typename std::enable_if<detail::result_is_implicit_copy_convertible<T, E, T2, E2>::value, int>::type = 0> 1569 result(const result<T2, E2>& other) noexcept( 1570 std::is_nothrow_constructible<T, const T2&>::value&& std::is_nothrow_constructible<E, const E2&>::value); 1571 template<typename T2, 1572 typename E2, 1573 typename std::enable_if<detail::result_is_explicit_copy_convertible<T, E, T2, E2>::value, int>::type = 0> 1574 explicit result(const result<T2, E2>& other) noexcept( 1575 std::is_nothrow_constructible<T, const T2&>::value&& std::is_nothrow_constructible<E, const E2&>::value); 1576 /// \} 1577 1578 /// \{ 1579 /// \brief Converting move constructor 1580 /// 1581 /// If \p other contains a value, constructs a result object 1582 /// that contains a value, initialized as if direct-initializing 1583 /// (but not direct-list-initializing) an object of type T with the 1584 /// expression `std::move(*other)`. 1585 /// 1586 /// If \p other contains an error, constructs a result object that 1587 /// contains an error, initialized as if direct-initializing 1588 /// (but not direct-list-initializing) an object of type E&&. 1589 /// 1590 /// \note This constructor does not participate in overload resolution 1591 /// unless the following conditions are met: 1592 /// - `std::is_constructible_v<T, const U&>` is `true` 1593 /// - T is not constructible or convertible from any expression 1594 /// of type (possibly const) `result<T2,E2>` 1595 /// - E is not constructible or convertible from any expression 1596 /// of type (possible const) `result<T2,E2>` 1597 /// 1598 /// \note This constructor is explicit if and only if 1599 /// `std::is_convertible_v<const T2&, T>` or 1600 /// `std::is_convertible_v<const E2&, E>` is `false` 1601 /// 1602 /// ### Examples 1603 /// 1604 /// Basic Usage: 1605 /// 1606 /// ```cpp 1607 /// auto r = cpp::result<std::unique_ptr<Derived>,int>{ 1608 /// std::make_unique<Derived>() 1609 /// }; 1610 /// const auto s = cpp::result<std::unique_ptr<Base>,long>{ 1611 /// std::move(r) 1612 /// }; 1613 /// ``` 1614 /// 1615 /// \param other the other type to convert 1616 template<typename T2, 1617 typename E2, 1618 typename std::enable_if<detail::result_is_implicit_move_convertible<T, E, T2, E2>::value, int>::type = 0> 1619 result(result<T2, E2>&& other) noexcept( 1620 std::is_nothrow_constructible<T, T2&&>::value&& std::is_nothrow_constructible<E, E2&&>::value); 1621 template<typename T2, 1622 typename E2, 1623 typename std::enable_if<detail::result_is_explicit_move_convertible<T, E, T2, E2>::value, int>::type = 0> 1624 explicit result(result<T2, E2>&& other) noexcept( 1625 std::is_nothrow_constructible<T, T2&&>::value&& std::is_nothrow_constructible<E, E2&&>::value); 1626 /// \} 1627 1628 //------------------------------------------------------------------------- 1629 1630 /// \brief Constructs a result object that contains a value 1631 /// 1632 /// The value is initialized as if direct-initializing (but not 1633 /// direct-list-initializing) an object of type `T` from the arguments 1634 /// `std::forward<Args>(args)...` 1635 /// 1636 /// ### Examples 1637 /// 1638 /// Basic Usage: 1639 /// 1640 /// ```cpp 1641 /// auto r = cpp::result<std::string,int>{ 1642 /// cpp::in_place, "Hello world" 1643 /// }; 1644 /// ``` 1645 /// 1646 /// \param args the arguments to pass to T's constructor 1647 template<typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type> 1648 constexpr explicit result(in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value); 1649 1650 /// \brief Constructs a result object that contains a value 1651 /// 1652 /// The value is initialized as if direct-initializing (but not 1653 /// direct-list-initializing) an object of type `T` from the arguments 1654 /// `std::forward<std::initializer_list<U>>(ilist)`, 1655 /// `std::forward<Args>(args)...` 1656 /// 1657 /// ### Examples 1658 /// 1659 /// Basic Usage: 1660 /// 1661 /// ```cpp 1662 /// auto r = cpp::result<std::string,int>{ 1663 /// cpp::in_place, {'H','e','l','l','o'} 1664 /// }; 1665 /// ``` 1666 /// 1667 /// \param ilist An initializer list of entries to forward 1668 /// \param args the arguments to pass to T's constructor 1669 template< 1670 typename U, 1671 typename... Args, 1672 typename = typename std::enable_if<std::is_constructible<T, std::initializer_list<U>&, Args...>::value>::type> 1673 constexpr explicit result(in_place_t, std::initializer_list<U> ilist, Args&&...args) noexcept( 1674 std::is_nothrow_constructible<T, std::initializer_list<U>, Args...>::value); 1675 1676 //------------------------------------------------------------------------- 1677 1678 /// \brief Constructs a result object that contains an error 1679 /// 1680 /// the value is initialized as if direct-initializing (but not 1681 /// direct-list-initializing) an object of type `E` from the arguments 1682 /// `std::forward<Args>(args)...` 1683 /// 1684 /// ### Examples 1685 /// 1686 /// Basic Usage: 1687 /// 1688 /// ```cpp 1689 /// auto r = cpp::result<int,std::string>{ 1690 /// cpp::in_place_error, "Hello world" 1691 /// }; 1692 /// ``` 1693 /// 1694 /// \param args the arguments to pass to E's constructor 1695 template<typename... Args, typename = typename std::enable_if<std::is_constructible<E, Args...>::value>::type> 1696 constexpr explicit result(in_place_error_t, 1697 Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 1698 1699 /// \brief Constructs a result object that contains an error 1700 /// 1701 /// The value is initialized as if direct-initializing (but not 1702 /// direct-list-initializing) an object of type `E` from the arguments 1703 /// `std::forward<std::initializer_list<U>>(ilist)`, 1704 /// `std::forward<Args>(args)...` 1705 /// 1706 /// ### Examples 1707 /// 1708 /// Basic Usage: 1709 /// 1710 /// ```cpp 1711 /// auto r = cpp::result<int,std::string>{ 1712 /// cpp::in_place_error, {'H','e','l','l','o'} 1713 /// }; 1714 /// ``` 1715 /// 1716 /// \param ilist An initializer list of entries to forward 1717 /// \param args the arguments to pass to Es constructor 1718 template< 1719 typename U, 1720 typename... Args, 1721 typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>&, Args...>::value>::type> 1722 constexpr explicit result(in_place_error_t, std::initializer_list<U> ilist, Args&&...args) noexcept( 1723 std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value); 1724 1725 //------------------------------------------------------------------------- 1726 1727 /// \{ 1728 /// \brief Constructs the underlying error of this result 1729 /// 1730 /// \note This constructor only participates in overload resolution if 1731 /// `E` is constructible from \p e 1732 /// 1733 /// ### Examples 1734 /// 1735 /// Basic Usage: 1736 /// 1737 /// ```cpp 1738 /// cpp::result<int,int> r = cpp::fail(42); 1739 /// 1740 /// auto get_error_result() -> cpp::result<int,std::string> { 1741 /// return cpp::fail("hello world!"); 1742 /// } 1743 /// ``` 1744 /// 1745 /// \param e the failure error 1746 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, const E2&>::value>::type> 1747 constexpr /* implicit */ result(const failure<E2>& e) noexcept(std::is_nothrow_constructible<E, const E2&>::value); 1748 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2&&>::value>::type> 1749 constexpr /* implicit */ result(failure<E2>&& e) noexcept(std::is_nothrow_constructible<E, E2&&>::value); 1750 /// \} 1751 1752 /// \{ 1753 /// \brief Constructs a result object that contains a value 1754 /// 1755 /// The value is initialized as if direct-initializing (but not 1756 /// direct-list-initializing) an object of type T with the expression 1757 /// value. 1758 /// 1759 /// \note This constructor is constexpr if the constructor of T 1760 /// selected by direct-initialization is constexpr 1761 /// 1762 /// \note This constructor does not participate in overload 1763 /// resolution unless `std::is_constructible_v<T, U&&>` is true 1764 /// and `decay_t<U>` is neither `in_place_t`, `in_place_error_t`, 1765 /// nor a `result` type. 1766 /// 1767 /// \note This constructor is explicit if and only if 1768 /// `std::is_convertible_v<U&&, T>` is `false` 1769 /// 1770 /// ### Examples 1771 /// 1772 /// Basic Usage: 1773 /// 1774 /// ```cpp 1775 /// cpp::result<int,int> r = 42; 1776 /// 1777 /// auto get_value() -> cpp::result<std::string,int> { 1778 /// return "hello world!"; // implicit conversion 1779 /// } 1780 /// ``` 1781 /// 1782 /// \param value the value to copy 1783 template<typename U, 1784 typename std::enable_if<detail::result_is_explicit_value_convertible<T, U>::value, int>::type = 0> 1785 constexpr explicit result(U&& value) noexcept(std::is_nothrow_constructible<T, U>::value); 1786 template<typename U, 1787 typename std::enable_if<detail::result_is_implicit_value_convertible<T, U>::value, int>::type = 0> 1788 constexpr /* implicit */ result(U&& value) noexcept(std::is_nothrow_constructible<T, U>::value); 1789 /// \} 1790 1791 //------------------------------------------------------------------------- 1792 1793 /// \brief Copy assigns the result stored in \p other 1794 /// 1795 /// \note This assignment operator only participates in overload resolution 1796 /// if the following conditions are met: 1797 /// - `std::is_nothrow_copy_constructible_v<T>` is `true`, and 1798 /// - `std::is_nothrow_copy_constructible_v<E>` is `true` 1799 /// this restriction guarantees that no ' 1800 /// 1801 /// \note This assignment operator is defined as trivial if the following 1802 /// conditions are all `true`: 1803 /// - `std::is_trivially_copy_constructible<T>::value` 1804 /// - `std::is_trivially_copy_constructible<E>::value` 1805 /// - `std::is_trivially_copy_assignable<T>::value` 1806 /// - `std::is_trivially_copy_assignable<E>::value` 1807 /// - `std::is_trivially_destructible<T>::value` 1808 /// - `std::is_trivially_destructible<E>::value` 1809 /// 1810 /// \param other the other result to copy 1811 auto operator=(const result& other) -> result& = default; 1812 1813 /// \brief Move assigns the result stored in \p other 1814 /// 1815 /// \note This assignment operator only participates in overload resolution 1816 /// if the following conditions are met: 1817 /// - `std::is_nothrow_copy_constructible_v<T>` is `true`, and 1818 /// - `std::is_nothrow_copy_constructible_v<E>` is `true` 1819 /// this restriction guarantees that no 'valueless_by_exception` state 1820 /// may occur. 1821 /// 1822 /// \note This assignment operator is defined as trivial if the following 1823 /// conditions are all `true`: 1824 /// - `std::is_trivially_move_constructible<T>::value` 1825 /// - `std::is_trivially_move_constructible<E>::value` 1826 /// - `std::is_trivially_move_assignable<T>::value` 1827 /// - `std::is_trivially_move_assignable<E>::value` 1828 /// - `std::is_trivially_destructible<T>::value` 1829 /// - `std::is_trivially_destructible<E>::value` 1830 /// 1831 /// \param other the other result to copy 1832 auto operator=(result&& other) -> result& = default; 1833 1834 /// \brief Copy-converts the state of \p other 1835 /// 1836 /// If both `*this` and \p other contain either values or errors, the 1837 /// underlying value is constructed as if through assignment. 1838 /// 1839 /// Otherwise if `*this` contains a value, but \p other contains an error, 1840 /// then the contained value is destroyed by calling its destructor. `*this` 1841 /// will no longer contain a value after the call, and will now contain `E` 1842 /// constructed as if direct-initializing (but not direct-list-initializing) 1843 /// an object with an argument of `const E2&`. 1844 /// 1845 /// If \p other contains a value and `*this` contains an error, then the 1846 /// contained error is destroyed by calling its destructor. `*this` now 1847 /// contains a value constructed as if direct-initializing (but not 1848 /// direct-list-initializing) an object with an argument of `const T2&`. 1849 /// 1850 /// \note The function does not participate in overload resolution unless 1851 /// - `std::is_nothrow_constructible_v<T, const T2&>`, 1852 /// `std::is_assignable_v<T&, const T2&>`, 1853 /// `std::is_nothrow_constructible_v<E, const E2&>`, 1854 /// `std::is_assignable_v<E&, const E2&>` are all true. 1855 /// - T is not constructible, convertible, or assignable from any 1856 /// expression of type (possibly const) `result<T2,E2>` 1857 /// 1858 /// \param other the other result object to convert 1859 /// \return reference to `(*this)` 1860 template<typename T2, 1861 typename E2, 1862 typename = typename std::enable_if<detail::result_is_copy_convert_assignable<T, E, T2, E2>::value>::type> 1863 auto operator=(const result<T2, E2>& other) noexcept( 1864 std::is_nothrow_assignable<T, const T2&>::value&& std::is_nothrow_assignable<E, const E2&>::value) -> result&; 1865 1866 /// \brief Move-converts the state of \p other 1867 /// 1868 /// If both `*this` and \p other contain either values or errors, the 1869 /// underlying value is constructed as if through move-assignment. 1870 /// 1871 /// Otherwise if `*this` contains a value, but \p other contains an error, 1872 /// then the contained value is destroyed by calling its destructor. `*this` 1873 /// will no longer contain a value after the call, and will now contain `E` 1874 /// constructed as if direct-initializing (but not direct-list-initializing) 1875 /// an object with an argument of `E2&&`. 1876 /// 1877 /// If \p other contains a value and `*this` contains an error, then the 1878 /// contained error is destroyed by calling its destructor. `*this` now 1879 /// contains a value constructed as if direct-initializing (but not 1880 /// direct-list-initializing) an object with an argument of `T2&&`. 1881 /// 1882 /// \note The function does not participate in overload resolution unless 1883 /// - `std::is_nothrow_constructible_v<T, T2&&>`, 1884 /// `std::is_assignable_v<T&, T2&&>`, 1885 /// `std::is_nothrow_constructible_v<E, E2&&>`, 1886 /// `std::is_assignable_v<E&, E2&&>` are all true. 1887 /// - T is not constructible, convertible, or assignable from any 1888 /// expression of type (possibly const) `result<T2,E2>` 1889 /// 1890 /// \param other the other result object to convert 1891 /// \return reference to `(*this)` 1892 template<typename T2, 1893 typename E2, 1894 typename = typename std::enable_if<detail::result_is_move_convert_assignable<T, E, T2, E2>::value>::type> 1895 auto operator=(result<T2, E2>&& other) noexcept( 1896 std::is_nothrow_assignable<T, T2&&>::value&& std::is_nothrow_assignable<E, E2&&>::value) -> result&; 1897 1898 /// \brief Perfect-forwarded assignment 1899 /// 1900 /// Depending on whether `*this` contains a value before the call, the 1901 /// contained value is either direct-initialized from std::forward<U>(value) 1902 /// or assigned from std::forward<U>(value). 1903 /// 1904 /// \note The function does not participate in overload resolution unless 1905 /// - `std::decay_t<U>` is not a result type, 1906 /// - `std::decay_t<U>` is not a failure type 1907 /// - `std::is_nothrow_constructible_v<T, U>` is `true` 1908 /// - `std::is_assignable_v<T&, U>` is `true` 1909 /// - and at least one of the following is `true`: 1910 /// - `T` is not a scalar type; 1911 /// - `std::decay_t<U>` is not `T`. 1912 /// 1913 /// \param value to assign to the contained value 1914 /// \return reference to `(*this)` 1915 template<typename U, typename = typename std::enable_if<detail::result_is_value_assignable<T, U>::value>::type> 1916 auto operator=(U&& value) noexcept(std::is_nothrow_assignable<T, U>::value) -> result&; 1917 1918 /// \{ 1919 /// \brief Perfect-forwarded assignment 1920 /// 1921 /// Depending on whether `*this` contains an error before the call, the 1922 /// contained error is either direct-initialized via forwarding the error, 1923 /// or assigned from forwarding the error 1924 /// 1925 /// \note The function does not participate in overload resolution unless 1926 /// - `std::is_nothrow_constructible_v<E, E2>` is `true`, and 1927 /// - `std::is_assignable_v<E&, E2>` is `true` 1928 /// 1929 /// \param other the failure value to assign to this 1930 /// \return reference to `(*this)` 1931 template<typename E2, 1932 typename = typename std::enable_if<detail::result_is_failure_assignable<E, const E2&>::value>::type> 1933 auto operator=(const failure<E2>& other) noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&; 1934 template<typename E2, 1935 typename = typename std::enable_if<detail::result_is_failure_assignable<E, E2&&>::value>::type> 1936 auto operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&; 1937 /// \} 1938 1939 //------------------------------------------------------------------------- 1940 // Observers 1941 //------------------------------------------------------------------------- 1942 public: 1943 /// \{ 1944 /// \brief Retrieves a pointer to the contained value 1945 /// 1946 /// This operator exists to give `result` an `optional`-like API for cases 1947 /// where it's known that the `result` already contains a value. 1948 /// 1949 /// Care must be taken to ensure that this is only used in safe contexts 1950 /// where a `T` value is active. 1951 /// 1952 /// \note The behavior is undefined if `*this` does not contain a value. 1953 /// 1954 /// ### Examples 1955 /// 1956 /// Basic Usage: 1957 /// 1958 /// ```cpp 1959 /// auto r = cpp::result<Widget,int>{ 1960 /// make_widget() 1961 /// }; 1962 /// 1963 /// r->do_something(); 1964 /// ``` 1965 /// 1966 /// \return a pointer to the contained value 1967 RESULT_WARN_UNUSED 1968 RESULT_CPP14_CONSTEXPR auto operator->() noexcept -> typename std::remove_reference<T>::type *; 1969 RESULT_WARN_UNUSED 1970 constexpr auto operator->() const noexcept -> 1971 typename std::remove_reference<typename std::add_const<T>::type>::type *; 1972 /// \} 1973 1974 /// \{ 1975 /// \brief Retrieves a reference to the contained value 1976 /// 1977 /// This operator exists to give `result` an `optional`-like API for cases 1978 /// where it's known that the `result` already contains a value. 1979 /// 1980 /// Care must be taken to ensure that this is only used in safe contexts 1981 /// where a `T` value is active. 1982 /// 1983 /// \note The behaviour is undefined if `*this` does not contain a value 1984 /// 1985 /// ### Examples 1986 /// 1987 /// Basic Usage: 1988 /// 1989 /// ```cpp 1990 /// auto r = cpp::result<Widget,int>{ 1991 /// make_widget() 1992 /// }; 1993 /// 1994 /// (*r).do_something(); 1995 /// 1996 /// consume(*r); 1997 /// ``` 1998 /// 1999 /// \return a reference to the contained value 2000 RESULT_WARN_UNUSED 2001 RESULT_CPP14_CONSTEXPR auto operator*() & noexcept -> typename std::add_lvalue_reference<T>::type; 2002 RESULT_WARN_UNUSED 2003 RESULT_CPP14_CONSTEXPR auto operator*() && noexcept -> typename std::add_rvalue_reference<T>::type; 2004 RESULT_WARN_UNUSED 2005 constexpr auto operator*() const& noexcept -> 2006 typename std::add_lvalue_reference<typename std::add_const<T>::type>::type; 2007 RESULT_WARN_UNUSED 2008 constexpr auto operator*() const&& noexcept -> 2009 typename std::add_rvalue_reference<typename std::add_const<T>::type>::type; 2010 /// \} 2011 2012 //------------------------------------------------------------------------- 2013 2014 /// \brief Contextually convertible to `true` if `*this` contains a value 2015 /// 2016 /// This function exists to allow for simple, terse checks for containing 2017 /// a value. 2018 /// 2019 /// ### Examples 2020 /// 2021 /// Basic Usage: 2022 /// 2023 /// ```cpp 2024 /// auto get_result() -> cpp::result<int, int>; 2025 /// auto r = get_result(); 2026 /// if (r) { ... } 2027 /// 2028 /// assert(static_cast<bool>(cpp::result<int,int>{42})); 2029 /// 2030 /// assert(!static_cast<bool>(cpp::result<int,int>{cpp::fail(42)})); 2031 /// ``` 2032 /// 2033 /// \return `true` if `*this` contains a value, `false` if `*this` 2034 /// does not contain a value 2035 RESULT_WARN_UNUSED 2036 constexpr explicit operator bool() const noexcept; 2037 2038 /// \brief Returns `true` if `*this` contains a value 2039 /// 2040 /// ### Examples 2041 /// 2042 /// Basic Usage: 2043 /// 2044 /// ```cpp 2045 /// auto get_result() -> cpp::result<int, int>; 2046 /// auto r = get_result(); 2047 /// if (r.has_value()) { ... } 2048 /// 2049 /// assert(cpp::result<int,int>{42}.has_value()); 2050 /// 2051 /// assert(!cpp::result<int,int>{cpp::fail(42)}.has_value()); 2052 /// ``` 2053 /// 2054 /// \return `true` if `*this` contains a value, `false` if `*this` 2055 /// contains an error 2056 RESULT_WARN_UNUSED 2057 constexpr auto has_value() const noexcept -> bool; 2058 2059 /// \brief Returns `true` if `*this` contains an error 2060 /// 2061 /// ### Examples 2062 /// 2063 /// Basic Usage: 2064 /// 2065 /// ```cpp 2066 /// auto get_result() -> cpp::result<int, int>; 2067 /// 2068 /// auto r = get_result(); 2069 /// if (r.has_error()) { ... } 2070 /// 2071 /// assert(!cpp::result<int,int>{42}.has_error()); 2072 /// 2073 /// assert(cpp::result<int,int>{cpp::fail(42)}.has_error()); 2074 /// ``` 2075 /// 2076 /// \return `true` if `*this` contains an error, `false` if `*this` 2077 /// contains a value 2078 RESULT_WARN_UNUSED 2079 constexpr auto has_error() const noexcept -> bool; 2080 2081 //------------------------------------------------------------------------- 2082 2083 /// \{ 2084 /// \brief Returns a reference to the contained value 2085 /// 2086 /// This function provides checked (throwing) access to the underlying 2087 /// value. The constness and refness of this result is propagated to the 2088 /// underlying reference. 2089 /// 2090 /// If this contains an error, an exception is thrown containing the 2091 /// underlying error. The error is consumed propagating the same constness 2092 /// and refness of this result. 2093 /// 2094 /// ### Examples 2095 /// 2096 /// Basic Usage: 2097 /// 2098 /// ```cpp 2099 /// assert(cpp::result<int,int>{42}.value() == 42); 2100 /// 2101 /// auto r = cpp::result<std::unique_ptr<int>,int>{ 2102 /// std::make_unique<int>(42) 2103 /// }; 2104 /// auto s = std::move(r).value(); 2105 /// 2106 /// try { 2107 /// auto r = cpp::result<int,int>{ cpp::fail(42) }; 2108 /// auto v = r.value(); 2109 /// } catch (const cpp::bad_result_access<int>& e) { 2110 /// assert(e.error() == 42); 2111 /// } 2112 /// ``` 2113 /// 2114 /// \throws bad_result_access<E> if `*this` does not contain a value. 2115 /// 2116 /// \return the value of `*this` 2117 RESULT_WARN_UNUSED 2118 RESULT_CPP14_CONSTEXPR auto value() & -> typename std::add_lvalue_reference<T>::type; 2119 RESULT_WARN_UNUSED 2120 RESULT_CPP14_CONSTEXPR auto value() && -> typename std::add_rvalue_reference<T>::type; 2121 RESULT_WARN_UNUSED 2122 constexpr auto value() const& -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type; 2123 RESULT_WARN_UNUSED 2124 constexpr auto value() const&& -> typename std::add_rvalue_reference<typename std::add_const<T>::type>::type; 2125 /// \} 2126 2127 /// \{ 2128 /// \brief Returns the contained error, if one exists, or a 2129 /// default-constructed error value 2130 /// 2131 /// The `error()` function will not throw any exceptions if `E` does not 2132 /// throw any exceptions for the copy or move construction. 2133 /// 2134 /// This is to limit the possible scope for exceptions, and to allow the 2135 /// error type to be treated as a "status"-like type, where the 2136 /// default-constructed case is considered the "good" state. 2137 /// 2138 /// If this function is invoked on an rvalue of a result, the error is 2139 /// returned via move-construction 2140 /// 2141 /// ### Requires 2142 /// 2143 /// * `std::is_default_constructible<E>::value` is `true` 2144 /// * `std::is_copy_constructible<E>::value` or 2145 /// `std::is_move_constructible<E>::value` is `true` 2146 /// * `E{}` represents the "good" (non-error) state 2147 /// 2148 /// ### Examples 2149 /// 2150 /// Basic Usage: 2151 /// 2152 /// ```cpp 2153 /// auto r = cpp::result<int,std::error_code>{ 42 }; 2154 /// assert(r.error() == std::error_code{}); 2155 /// 2156 /// auto r = cpp::result<int,std::error_code>{ 2157 /// cpp::fail(std::io_errc::stream) 2158 /// }; 2159 /// 2160 /// assert(r.error() == std::io_errc::stream); 2161 /// ``` 2162 /// 2163 /// \return the error or a default-constructed error value 2164 RESULT_WARN_UNUSED 2165 constexpr auto 2166 error() const& noexcept(std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) 2167 -> E; 2168 RESULT_WARN_UNUSED 2169 RESULT_CPP14_CONSTEXPR auto 2170 error() && noexcept(std::is_nothrow_constructible<E>::value&& std::is_nothrow_move_constructible<E>::value) -> E; 2171 /// } 2172 2173 /// \{ 2174 /// \brief Asserts an expectation that this result contains an error, 2175 /// throwing a bad_result_access on failure 2176 /// 2177 /// If this function is invoked from an rvalue of `result`, then this will 2178 /// consume the underlying error first, if there is one. 2179 /// 2180 /// \note This function exists as a means to allow for results to be marked 2181 /// `used` without requiring directly inspecting the underlying value. 2182 /// This is, in effect, equivalent to `assert(res.has_value())`, 2183 /// however it uses exceptions to ensure the stack can be unwound, and 2184 /// exceptions invoked. 2185 /// 2186 /// ### Examples 2187 /// 2188 /// Basic Usage: 2189 /// 2190 /// ```cpp 2191 /// auto start_service() -> cpp::result<void,int>; 2192 /// 2193 /// start_service().expect("Service failed to start!"); 2194 /// ``` 2195 /// 2196 /// \param message the message to provide to this expectation 2197 template<typename String, 2198 typename = typename std::enable_if<(std::is_convertible<String, const std::string&>::value 2199 && std::is_copy_constructible<E>::value)>::type> 2200 RESULT_CPP14_CONSTEXPR auto expect(String&& message) const& -> void; 2201 template<typename String, 2202 typename = typename std::enable_if<(std::is_convertible<String, const std::string&>::value 2203 && std::is_move_constructible<E>::value)>::type> 2204 RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> void; 2205 /// \} 2206 2207 //------------------------------------------------------------------------- 2208 // Monadic Functionalities 2209 //------------------------------------------------------------------------- 2210 public: 2211 /// \{ 2212 /// \brief Returns the contained value if `*this` has a value, 2213 /// otherwise returns \p default_value. 2214 /// 2215 /// ### Examples 2216 /// 2217 /// Basic Usage: 2218 /// 2219 /// ```cpp 2220 /// auto r = cpp::result<int,int>{42}; 2221 /// assert(r.value_or(0) == 42); 2222 /// 2223 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2224 /// assert(r.value_or(0) == 0); 2225 /// ``` 2226 /// 2227 /// \param default_value the value to use in case `*this` contains an error 2228 /// \return the contained value or \p default_value 2229 template<typename U> 2230 RESULT_WARN_UNUSED constexpr auto value_or(U&& default_value) const& -> typename std::remove_reference<T>::type; 2231 template<typename U> 2232 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto value_or(U&& default_value) && -> 2233 typename std::remove_reference<T>::type; 2234 /// \} 2235 2236 /// \{ 2237 /// \brief Returns the contained error if `*this` has an error, 2238 /// otherwise returns \p default_error. 2239 /// 2240 /// ### Examples 2241 /// 2242 /// Basic Usage: 2243 /// 2244 /// ```cpp 2245 /// auto r = cpp::result<int,int>{42}; 2246 /// assert(r.error_or(0) == cpp::fail(0)); 2247 /// 2248 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2249 /// assert(r.error_or(0) == cpp::fail(42)); 2250 /// ``` 2251 /// 2252 /// \param default_error the error to use in case `*this` is empty 2253 /// \return the contained value or \p default_error 2254 template<typename U> 2255 RESULT_WARN_UNUSED constexpr auto error_or(U&& default_error) const& -> error_type; 2256 template<typename U> 2257 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type; 2258 /// \} 2259 2260 //------------------------------------------------------------------------- 2261 2262 /// \brief Returns a result containing \p value if this result contains 2263 /// a value, otherwise returns a result containing the current 2264 /// error. 2265 /// 2266 /// ### Examples 2267 /// 2268 /// Basic Usage: 2269 /// 2270 /// ```cpp 2271 /// auto r = cpp::result<int,int>{42}; 2272 /// assert(r.and_then(100) == 100); 2273 /// 2274 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2275 /// assert(r.and_then(100) == cpp::fail(42)); 2276 /// ``` 2277 /// 2278 /// \param value the value to return as a result 2279 /// \return a result of \p value if this contains a value 2280 template<typename U> 2281 RESULT_WARN_UNUSED constexpr auto and_then(U&& value) const -> result<typename std::decay<U>::type, E>; 2282 2283 /// \{ 2284 /// \brief Invokes the function \p fn with the value of this result as 2285 /// the argument 2286 /// 2287 /// If this result contains an error, a result of the error is returned 2288 /// 2289 /// The function being called must return a `result` type or the program 2290 /// is ill-formed 2291 /// 2292 /// If this is called on an rvalue of `result` which contains an error, 2293 /// the returned `result` is constructed from an rvalue of that error. 2294 /// 2295 /// ### Examples 2296 /// 2297 /// Basic Usage: 2298 /// 2299 /// ```cpp 2300 /// auto to_string(int) -> cpp::result<std::string,int>; 2301 /// auto r = cpp::result<int,int>{42}; 2302 /// assert(r.flat_map(to_string) == "42"); 2303 /// 2304 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2305 /// assert(r.flat_map(to_string) == cpp::fail(42)); 2306 /// ``` 2307 /// 2308 /// \param fn the function to invoke with this 2309 /// \return The result of the function being called 2310 template<typename Fn> 2311 RESULT_WARN_UNUSED constexpr auto flat_map(Fn&& fn) const& -> detail::invoke_result_t<Fn, const T&>; 2312 template<typename Fn> 2313 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn, T&&>; 2314 /// \} 2315 2316 /// \{ 2317 /// \brief Invokes the function \p fn with the value of this result as 2318 /// the argument 2319 /// 2320 /// If this result is an error, the result of this function is that 2321 /// error. Otherwise this function wraps the result and returns it as an 2322 /// result. 2323 /// 2324 /// If this is called on an rvalue of `result` which contains an error, 2325 /// the returned `result` is constructed from an rvalue of that error. 2326 /// 2327 /// ### Examples 2328 /// 2329 /// Basic Usage: 2330 /// 2331 /// ```cpp 2332 /// auto to_string(int) -> std::string; 2333 /// auto r = cpp::result<int,int>{42}; 2334 /// assert(r.map(to_string) == "42"); 2335 /// 2336 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2337 /// assert(r.map(to_string) == cpp::fail(42)); 2338 /// ``` 2339 /// 2340 /// \param fn the function to invoke with this 2341 /// \return The result result of the function invoked 2342 template<typename Fn> 2343 RESULT_WARN_UNUSED constexpr auto map(Fn&& fn) const& -> result<detail::invoke_result_t<Fn, const T&>, E>; 2344 template<typename Fn> 2345 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result<detail::invoke_result_t<Fn, T&&>, E>; 2346 /// \} 2347 2348 /// \{ 2349 /// \brief Invokes the function \p fn with the error of this result as 2350 /// the argument 2351 /// 2352 /// If this result contains a value, the result of this function is that 2353 /// value. Otherwise the function is called with that error and returns the 2354 /// result as a result. 2355 /// 2356 /// If this is called on an rvalue of `result` which contains a value, 2357 /// the returned `result` is constructed from an rvalue of that value. 2358 /// 2359 /// ### Examples 2360 /// 2361 /// Basic Usage: 2362 /// 2363 /// ```cpp 2364 /// auto to_string(int) -> std::string; 2365 /// auto r = cpp::result<int,int>{42}; 2366 /// assert(r.map_error(to_string) == 42); 2367 /// 2368 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2369 /// assert(r.map_error(to_string) == cpp::fail("42")); 2370 /// 2371 /// auto r = cpp::result<std::string,int>{}; 2372 /// auto s = r.map(std::string::size); // 's' contains 'result<size_t,int>' 2373 /// ``` 2374 /// 2375 /// \param fn the function to invoke with this 2376 /// \return The result result of the function invoked 2377 template<typename Fn> 2378 RESULT_WARN_UNUSED constexpr auto map_error(Fn&& fn) const& -> result<T, detail::invoke_result_t<Fn, const E&>>; 2379 template<typename Fn> 2380 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto map_error(Fn&& fn) && -> result<T, detail::invoke_result_t<Fn, E&&>>; 2381 /// \} 2382 2383 /// \{ 2384 /// \brief Invokes the function \p fn with the error of this result as 2385 /// the argument 2386 /// 2387 /// If this result contains a value, a result of the value is returned 2388 /// 2389 /// The function being called must return a `result` type or the program 2390 /// is ill-formed 2391 /// 2392 /// If this is called on an rvalue of `result` which contains an error, 2393 /// the returned `result` is constructed from an rvalue of that error. 2394 /// 2395 /// ### Examples 2396 /// 2397 /// Basic Usage: 2398 /// 2399 /// ```cpp 2400 /// auto to_string(int) -> cpp::result<int,std::string>; 2401 /// auto r = cpp::result<int,int>{42}; 2402 /// assert(r.flat_map(to_string) == 42); 2403 /// 2404 /// auto r = cpp::result<int,int>{cpp::fail(42)}; 2405 /// assert(r.flat_map(to_string) == cpp::fail("42")); 2406 /// ``` 2407 /// 2408 /// \param fn the function to invoke with this 2409 /// \return The result of the function being called 2410 template<typename Fn> 2411 RESULT_WARN_UNUSED constexpr auto flat_map_error(Fn&& fn) const& -> detail::invoke_result_t<Fn, const E&>; 2412 template<typename Fn> 2413 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn) && -> detail::invoke_result_t<Fn, E&&>; 2414 /// \} 2415 2416 //------------------------------------------------------------------------- 2417 // Private Members 2418 //------------------------------------------------------------------------- 2419 private: 2420 detail::result_storage<T, E> m_storage; 2421 2422 //------------------------------------------------------------------------- 2423 // Private Monadic Functions 2424 //------------------------------------------------------------------------- 2425 private: 2426 /// \{ 2427 /// \brief Map implementations for void and non-void functions 2428 /// 2429 /// \param fn the function 2430 template<typename Fn> 2431 constexpr auto map_impl(std::true_type, Fn&& fn) const& -> result<void, E>; 2432 template<typename Fn> 2433 constexpr auto map_impl(std::false_type, Fn&& fn) const& -> result<detail::invoke_result_t<Fn, const T&>, E>; 2434 template<typename Fn> 2435 RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result<void, E>; 2436 template<typename Fn> 2437 RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn, T&&>, E>; 2438 /// \} 2439 }; 2440 2441 //=========================================================================== 2442 // class : result<void,E> 2443 //=========================================================================== 2444 2445 ///////////////////////////////////////////////////////////////////////////// 2446 /// \brief Partial specialization of `result<void, E>` 2447 /// 2448 /// \tparam E the underlying error type 2449 ///////////////////////////////////////////////////////////////////////////// 2450 template<typename E> 2451 class RESULT_NODISCARD result<void, E> { 2452 // Type requirements 2453 2454 static_assert(!std::is_void<typename std::decay<E>::type>::value, 2455 "It is ill-formed for E to be (possibly CV-qualified) void type"); 2456 static_assert(!std::is_abstract<E>::value, "It is ill-formed for E to be abstract type"); 2457 static_assert(!is_failure<typename std::decay<E>::type>::value, 2458 "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type"); 2459 static_assert(!std::is_reference<E>::value, 2460 "It is ill-formed for E to be a reference type. " 2461 "Only T types may be lvalue references"); 2462 2463 // Friendship 2464 2465 friend detail::result_error_extractor; 2466 2467 template<typename T2, typename E2> 2468 friend class result; 2469 2470 //------------------------------------------------------------------------- 2471 // Public Member Types 2472 //------------------------------------------------------------------------- 2473 public: 2474 using value_type = void; ///< The value type of this result 2475 using error_type = E; ///< The error type of this result 2476 using failure_type = failure<E>; ///< The failure type 2477 2478 template<typename U> 2479 using rebind = result<U, E>; ///< Rebinds the result type 2480 2481 //------------------------------------------------------------------------- 2482 // Constructor / Assignment 2483 //------------------------------------------------------------------------- 2484 public: 2485 /// \brief Constructs a `result` object in a value state 2486 /// 2487 /// ### Examples 2488 /// 2489 /// Basic Usage: 2490 /// 2491 /// ```cpp 2492 /// auto r = cpp::result<void,int>{}; 2493 /// ``` 2494 constexpr result() noexcept; 2495 2496 /// \brief Copy constructs this result 2497 /// 2498 /// If other contains an error, constructs an object that contains a copy 2499 /// of that error. 2500 /// 2501 /// \note This constructor is defined as deleted if 2502 /// `std::is_copy_constructible<E>::value` is `false` 2503 /// 2504 /// \note This constructor is defined as trivial if both 2505 /// `std::is_trivially_copy_constructible<E>::value` are `true` 2506 /// 2507 /// ### Examples 2508 /// 2509 /// Basic Usage: 2510 /// 2511 /// ```cpp 2512 /// const auto r = cpp::result<void,int>{}; 2513 /// const auto s = r; 2514 /// ``` 2515 /// 2516 /// \param other the result to copy 2517 constexpr result(const result& other) = default; 2518 2519 /// \brief Move constructs a result 2520 /// 2521 /// If other contains an error, move-constructs this result from that 2522 /// error. 2523 /// 2524 /// \note This constructor is defined as deleted if 2525 /// `std::is_move_constructible<E>::value` is `false` 2526 /// 2527 /// \note This constructor is defined as trivial if both 2528 /// `std::is_trivially_move_constructible<E>::value` are `true` 2529 /// 2530 /// ### Examples 2531 /// 2532 /// Basic Usage: 2533 /// 2534 /// ```cpp 2535 /// auto r = cpp::result<void,std::string>{}; 2536 /// auto s = std::move(r); 2537 /// ``` 2538 /// 2539 /// \param other the result to move 2540 constexpr result(result&& other) = default; 2541 2542 /// \brief Converting copy constructor 2543 /// 2544 /// If \p other contains a value, constructs a result object that is not 2545 /// in an error state -- ignoring the value. 2546 /// 2547 /// If \p other contains an error, constructs a result object that 2548 /// contains an error, initialized as if direct-initializing 2549 /// (but not direct-list-initializing) an object of type `E`. 2550 /// 2551 /// \note This constructor does not participate in overload resolution 2552 /// unless the following conditions are met: 2553 /// - `std::is_constructible_v<E, const E2&>` is `true` 2554 /// 2555 /// ### Examples 2556 /// 2557 /// Basic Usage: 2558 /// 2559 /// ```cpp 2560 /// const auto r = cpp::result<int,int>{42}; 2561 /// const auto s = cpp::result<void,int>{r}; 2562 /// ``` 2563 /// 2564 /// \param other the other type to convert 2565 template<typename U, typename E2, typename = typename std::enable_if<std::is_constructible<E, E2>::value>::type> 2566 explicit result(const result<U, E2>& other) noexcept(std::is_nothrow_constructible<E, const E2&>::value); 2567 2568 /// \brief Converting move constructor 2569 /// 2570 /// If \p other contains an error, constructs a result object that 2571 /// contains an error, initialized as if direct-initializing 2572 /// (but not direct-list-initializing) an object of type E&&. 2573 /// 2574 /// \note This constructor does not participate in overload resolution 2575 /// unless the following conditions are met: 2576 /// - `std::is_constructible_v<E, const E2&>` is `true` 2577 /// 2578 /// ### Examples 2579 /// 2580 /// Basic Usage: 2581 /// 2582 /// ```cpp 2583 /// auto r = cpp::result<int,std::string>{42}; 2584 /// auto s = cpp::result<void,std::string>{ 2585 /// std::move(r) 2586 /// }; 2587 /// ``` 2588 /// 2589 /// \param other the other type to convert 2590 template<typename U, typename E2, typename = typename std::enable_if<std::is_constructible<E, E2>::value>::type> 2591 explicit result(result<U, E2>&& other) noexcept(std::is_nothrow_constructible<E, E2&&>::value); 2592 2593 //------------------------------------------------------------------------- 2594 2595 /// \brief Constructs a result object in a value state 2596 /// 2597 /// This constructor exists primarily for symmetry with the `result<T,E>` 2598 /// constructor. Unlike the `T` overload, no variadic arguments may be 2599 /// supplied. 2600 /// 2601 /// ### Examples 2602 /// 2603 /// Basic Usage: 2604 /// 2605 /// ```cpp 2606 /// auto r = cpp::result<void,std::string>{cpp::in_place}; 2607 /// ``` 2608 constexpr explicit result(in_place_t) noexcept; 2609 2610 /// \brief Constructs a result object that contains an error 2611 /// 2612 /// the value is initialized as if direct-initializing (but not 2613 /// direct-list-initializing) an object of type `E` from the arguments 2614 /// `std::forward<Args>(args)...` 2615 /// 2616 /// ### Examples 2617 /// 2618 /// Basic Usage: 2619 /// 2620 /// ```cpp 2621 /// auto r = cpp::result<void,std::string>{ 2622 /// cpp::in_place_error, "Hello world" 2623 /// }; 2624 /// ``` 2625 /// 2626 /// \param args the arguments to pass to `E`'s constructor 2627 template<typename... Args, typename = typename std::enable_if<std::is_constructible<E, Args...>::value>::type> 2628 constexpr explicit result(in_place_error_t, 2629 Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value); 2630 2631 /// \brief Constructs a result object that contains an error 2632 /// 2633 /// The value is initialized as if direct-initializing (but not 2634 /// direct-list-initializing) an object of type `E` from the arguments 2635 /// `std::forward<std::initializer_list<U>>(ilist)`, 2636 /// `std::forward<Args>(args)...` 2637 /// 2638 /// ### Examples 2639 /// 2640 /// Basic Usage: 2641 /// 2642 /// ```cpp 2643 /// auto r = cpp::result<void,std::string>{ 2644 /// cpp::in_place_error, {'H','e','l','l','o'} 2645 /// }; 2646 /// ``` 2647 /// 2648 /// \param ilist An initializer list of entries to forward 2649 /// \param args the arguments to pass to Es constructor 2650 template< 2651 typename U, 2652 typename... Args, 2653 typename = typename std::enable_if<std::is_constructible<E, std::initializer_list<U>&, Args...>::value>::type> 2654 constexpr explicit result(in_place_error_t, std::initializer_list<U> ilist, Args&&...args) noexcept( 2655 std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value); 2656 2657 //------------------------------------------------------------------------- 2658 2659 /// \{ 2660 /// \brief Constructs the underlying error of this result 2661 /// 2662 /// \note This constructor only participates in overload resolution if 2663 /// `E` is constructible from \p e 2664 /// 2665 /// ### Examples 2666 /// 2667 /// Basic Usage: 2668 /// 2669 /// ```cpp 2670 /// cpp::result<void,int> r = cpp::fail(42); 2671 /// 2672 /// auto get_error_result() -> cpp::result<void,std::string> { 2673 /// return cpp::fail("hello world!"); 2674 /// } 2675 /// ``` 2676 /// 2677 /// \param e the failure error 2678 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, const E2&>::value>::type> 2679 constexpr /* implicit */ result(const failure<E2>& e) noexcept(std::is_nothrow_constructible<E, const E2&>::value); 2680 template<typename E2, typename = typename std::enable_if<std::is_constructible<E, E2&&>::value>::type> 2681 constexpr /* implicit */ result(failure<E2>&& e) noexcept(std::is_nothrow_constructible<E, E2&&>::value); 2682 /// \} 2683 2684 //------------------------------------------------------------------------- 2685 2686 /// \brief Copy assigns the result stored in \p other 2687 /// 2688 /// \note The function does not participate in overload resolution unless 2689 /// - `std::is_nothrow_copy_constructible_v<E>` is `true` 2690 /// this restriction guarantees that no 'valueless_by_exception` state 2691 /// may occur. 2692 /// 2693 /// \note This assignment operator is defined as trivial if the following 2694 /// conditions are all `true`: 2695 /// - `std::is_trivially_copy_constructible<E>::value` 2696 /// - `std::is_trivially_copy_assignable<E>::value` 2697 /// - `std::is_trivially_destructible<E>::value` 2698 /// 2699 /// \param other the other result to copy 2700 auto operator=(const result& other) -> result& = default; 2701 2702 /// \brief Move assigns the result stored in \p other 2703 /// 2704 /// \note The function does not participate in overload resolution unless 2705 /// - `std::is_nothrow_copy_constructible_v<E>` is `true` 2706 /// this restriction guarantees that no 'valueless_by_exception` state 2707 /// may occur. 2708 /// 2709 /// \note This assignment operator is defined as trivial if the following 2710 /// conditions are all `true`: 2711 /// - `std::is_trivially_move_constructible<E>::value` 2712 /// - `std::is_trivially_move_assignable<E>::value` 2713 /// - `std::is_trivially_destructible<E>::value` 2714 /// 2715 /// \param other the other result to copy 2716 auto operator=(result&& other) -> result& = default; 2717 2718 /// \brief Copy-converts the state of \p other 2719 /// 2720 /// If both this and \p other contain an error, the underlying error is 2721 /// assigned through copy-assignment. 2722 /// 2723 /// If \p other contains a value state, this result is constructed in a 2724 /// value state. 2725 /// 2726 /// If \p other contans an error state, and this contains a value state, 2727 /// the underlying error is constructed through copy-construction. 2728 /// 2729 /// \note The function does not participate in overload resolution unless 2730 /// - `std::is_nothrow_constructible_v<E, const E2&>`, 2731 /// `std::is_assignable_v<E&, const E2&>` are all `true`. 2732 /// 2733 /// \param other the other result object to convert 2734 /// \return reference to `(*this)` 2735 template<typename E2, 2736 typename = typename std::enable_if<std::is_nothrow_constructible<E, const E2&>::value 2737 && std::is_assignable<E&, const E2&>::value>::type> 2738 auto operator=(const result<void, E2>& other) noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&; 2739 2740 /// \brief Move-converts the state of \p other 2741 /// 2742 /// If both this and \p other contain an error, the underlying error is 2743 /// assigned through move-assignment. 2744 /// 2745 /// If \p other contains a value state, this result is constructed in a 2746 /// value state. 2747 /// 2748 /// If \p other contans an error state, and this contains a value state, 2749 /// the underlying error is constructed through move-construction. 2750 /// 2751 /// \note The function does not participate in overload resolution unless 2752 /// - `std::is_nothrow_constructible_v<E, E2&&>`, 2753 /// `std::is_assignable_v<E&, E2&&>` are all `true`. 2754 /// 2755 /// \param other the other result object to convert 2756 /// \return reference to `(*this)` 2757 template<typename E2, 2758 typename = typename std::enable_if<std::is_nothrow_constructible<E, E2&&>::value 2759 && std::is_assignable<E&, E2&&>::value>::type> 2760 auto operator=(result<void, E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&; 2761 2762 /// \{ 2763 /// \brief Perfect-forwarded assignment 2764 /// 2765 /// Depending on whether `*this` contains an error before the call, the 2766 /// contained error is either direct-initialized via forwarding the error, 2767 /// or assigned from forwarding the error 2768 /// 2769 /// \note The function does not participate in overload resolution unless 2770 /// - `std::is_nothrow_constructible_v<E, E2>` is `true`, and 2771 /// - `std::is_assignable_v<E&, E2>` is `true` 2772 /// 2773 /// \param other the failure value to assign to this 2774 /// \return reference to `(*this)` 2775 template<typename E2, 2776 typename = typename std::enable_if<detail::result_is_failure_assignable<E, const E2&>::value>::type> 2777 auto operator=(const failure<E2>& other) noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> result&; 2778 template<typename E2, 2779 typename = typename std::enable_if<detail::result_is_failure_assignable<E, E2&&>::value>::type> 2780 auto operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) -> result&; 2781 /// \} 2782 2783 //------------------------------------------------------------------------- 2784 // Observers 2785 //------------------------------------------------------------------------- 2786 public: 2787 /// \brief Contextually convertible to `true` if `*this` does not contain 2788 /// an error 2789 /// 2790 /// This function exists to allow for simple, terse checks for containing 2791 /// a value. 2792 /// 2793 /// ### Examples 2794 /// 2795 /// Basic Usage: 2796 /// 2797 /// ```cpp 2798 /// auto get_result() -> cpp::result<void, int>; 2799 /// auto r = get_result(); 2800 /// if (r) { ... } 2801 /// 2802 /// assert(static_cast<bool>(cpp::result<void,int>{})); 2803 /// 2804 /// assert(!static_cast<bool>(cpp::result<void,int>{cpp::fail(42)})); 2805 /// ``` 2806 /// 2807 /// \return `true` if `*this` contains a value, `false` if `*this` 2808 /// does not contain a value 2809 RESULT_WARN_UNUSED 2810 constexpr explicit operator bool() const noexcept; 2811 2812 /// \copydoc result<T,E>::has_value 2813 RESULT_WARN_UNUSED 2814 constexpr auto has_value() const noexcept -> bool; 2815 2816 /// \copydoc result<T,E>::has_error 2817 RESULT_WARN_UNUSED 2818 constexpr auto has_error() const noexcept -> bool; 2819 2820 //------------------------------------------------------------------------- 2821 2822 /// \{ 2823 /// \brief Throws an exception if `(*this)` is in an error state 2824 /// 2825 /// This function exists for symmetry with `cpp::result<T,E>` objects where 2826 /// `T` contains a value. 2827 /// 2828 /// If this contains an error, an exception is thrown containing the 2829 /// underlying error. The error is consumed propagating the same constness 2830 /// and refness of this result. 2831 /// 2832 /// ### Examples 2833 /// 2834 /// Basic Usage: 2835 /// 2836 /// ```cpp 2837 /// cpp::result<void,int>{}.value(); // no exception 2838 /// 2839 /// auto r = cpp::result<void,std::unique_ptr<int>>{ 2840 /// cpp::fail(std::make_unique<int>(42)) 2841 /// }; 2842 /// std::move(r).value(); // throws bad_result_access<std::unique_ptr<int>> 2843 /// 2844 /// try { 2845 /// auto r = cpp::result<void,int>{ cpp::fail(42) }.value(); 2846 /// } catch (const cpp::bad_result_access<int>& e) { 2847 /// assert(e.error() == 42); 2848 /// } 2849 /// ``` 2850 /// 2851 /// \throws bad_result_access<E> if `*this` does not contain a value. 2852 RESULT_CPP14_CONSTEXPR auto value() && -> void; 2853 RESULT_CPP14_CONSTEXPR auto value() const& -> void; 2854 /// \} 2855 2856 /// \{ 2857 /// \copydoc result<T,E>::error 2858 RESULT_WARN_UNUSED 2859 constexpr auto 2860 error() const& noexcept(std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) 2861 -> E; 2862 RESULT_WARN_UNUSED 2863 RESULT_CPP14_CONSTEXPR auto 2864 error() && noexcept(std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) -> E; 2865 /// \} 2866 2867 /// \{ 2868 /// \copydoc result<T,E>::expect 2869 template<typename String, 2870 typename = typename std::enable_if<(std::is_convertible<String, const std::string&>::value 2871 && std::is_copy_constructible<E>::value)>::type> 2872 RESULT_CPP14_CONSTEXPR auto expect(String&& message) const& -> void; 2873 template<typename String, 2874 typename = typename std::enable_if<(std::is_convertible<String, const std::string&>::value 2875 && std::is_move_constructible<E>::value)>::type> 2876 RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> void; 2877 /// \} 2878 2879 //------------------------------------------------------------------------- 2880 // Monadic Functionalities 2881 //------------------------------------------------------------------------- 2882 public: 2883 /// \{ 2884 /// \copydoc result<T,E>::error_or 2885 template<typename U> 2886 RESULT_WARN_UNUSED constexpr auto error_or(U&& default_error) const& -> error_type; 2887 template<typename U> 2888 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type; 2889 /// \} 2890 2891 //------------------------------------------------------------------------- 2892 2893 /// \copydoc result<T,E>::and_then 2894 template<typename U> 2895 RESULT_WARN_UNUSED constexpr auto and_then(U&& value) const -> result<typename std::decay<U>::type, E>; 2896 2897 /// \{ 2898 /// \brief Invokes the function \p fn if `(*this)` contains no value 2899 /// 2900 /// If this result contains an error, a result of the error is returned 2901 /// 2902 /// The function being called must return a `result` type or the program 2903 /// is ill-formed 2904 /// 2905 /// If this is called on an rvalue of `result` which contains an error, 2906 /// the returned `result` is constructed from an rvalue of that error. 2907 /// 2908 /// ### Examples 2909 /// 2910 /// Basic Usage: 2911 /// 2912 /// ```cpp 2913 /// auto generate_int() -> cpp::result<int,int> { return 42; } 2914 /// auto r = cpp::result<void,int>{}; 2915 /// assert(r.flat_map(generate_int) == 42); 2916 /// 2917 /// auto r = cpp::result<void,int>{cpp::fail(42)}; 2918 /// assert(r.flat_map(generate_int) == cpp::fail(42)); 2919 /// ``` 2920 /// 2921 /// \param fn the function to invoke with this 2922 /// \return The result of the function being called 2923 template<typename Fn> 2924 RESULT_WARN_UNUSED constexpr auto flat_map(Fn&& fn) const& -> detail::invoke_result_t<Fn>; 2925 template<typename Fn> 2926 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn>; 2927 /// \} 2928 2929 /// \{ 2930 /// \brief Invokes the function \p fn if `(*this)` contains no value 2931 /// 2932 /// If this result is an error, the result of this function is that 2933 /// error. Otherwise this function wraps the result and returns it as an 2934 /// result. 2935 /// 2936 /// If this is called on an rvalue of `result` which contains an error, 2937 /// the returned `result` is constructed from an rvalue of that error. 2938 /// 2939 /// ### Examples 2940 /// 2941 /// Basic Usage: 2942 /// 2943 /// ```cpp 2944 /// auto generate_int() -> int { return 42; } 2945 /// auto r = cpp::result<void,int>{}; 2946 /// assert(r.map(generate_int) == 42); 2947 /// 2948 /// auto r = cpp::result<void,int>{cpp::fail(42)}; 2949 /// assert(r.map(generate_int) == cpp::fail(42)); 2950 /// ``` 2951 /// 2952 /// \param fn the function to invoke with this 2953 /// \return The result result of the function invoked 2954 template<typename Fn> 2955 RESULT_WARN_UNUSED constexpr auto map(Fn&& fn) const& -> result<detail::invoke_result_t<Fn>, E>; 2956 template<typename Fn> 2957 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result<detail::invoke_result_t<Fn>, E>; 2958 /// \} 2959 2960 /// \{ 2961 /// \copydoc result<T,E>::map_error 2962 template<typename Fn> 2963 constexpr auto map_error(Fn&& fn) const& -> result<void, detail::invoke_result_t<Fn, const E&>>; 2964 template<typename Fn> 2965 RESULT_CPP14_CONSTEXPR auto map_error(Fn&& fn) && -> result<void, detail::invoke_result_t<Fn, E&&>>; 2966 /// \} 2967 2968 /// \{ 2969 /// \copydoc result<T,E>::flat_map_error 2970 template<typename Fn> 2971 RESULT_WARN_UNUSED constexpr auto flat_map_error(Fn&& fn) const& -> detail::invoke_result_t<Fn, const E&>; 2972 template<typename Fn> 2973 RESULT_WARN_UNUSED RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn) && -> detail::invoke_result_t<Fn, E&&>; 2974 /// \} 2975 2976 //------------------------------------------------------------------------- 2977 // Private Members 2978 //------------------------------------------------------------------------- 2979 private: 2980 detail::result_storage<detail::unit, E> m_storage; 2981 2982 //------------------------------------------------------------------------- 2983 // Private Monadic Functions 2984 //------------------------------------------------------------------------- 2985 private: 2986 /// \{ 2987 /// \brief Map implementations for void and non-void functions 2988 /// 2989 /// \param fn the function 2990 template<typename Fn> 2991 constexpr auto map_impl(std::true_type, Fn&& fn) const& -> result<void, E>; 2992 template<typename Fn> 2993 constexpr auto map_impl(std::false_type, Fn&& fn) const& -> result<detail::invoke_result_t<Fn>, E>; 2994 template<typename Fn> 2995 RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result<void, E>; 2996 template<typename Fn> 2997 RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn>, E>; 2998 /// \} 2999 }; 3000 3001 //=========================================================================== 3002 // non-member functions : class : result 3003 //=========================================================================== 3004 3005 //--------------------------------------------------------------------------- 3006 // Comparison 3007 //--------------------------------------------------------------------------- 3008 3009 template<typename T1, typename E1, typename T2, typename E2> 3010 constexpr auto operator==(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3011 template<typename T1, typename E1, typename T2, typename E2> 3012 constexpr auto operator!=(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3013 template<typename T1, typename E1, typename T2, typename E2> 3014 constexpr auto operator>=(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3015 template<typename T1, typename E1, typename T2, typename E2> 3016 constexpr auto operator<=(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3017 template<typename T1, typename E1, typename T2, typename E2> 3018 constexpr auto operator>(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3019 template<typename T1, typename E1, typename T2, typename E2> 3020 constexpr auto operator<(const result<T1, E1>& lhs, const result<T2, E2>& rhs) noexcept -> bool; 3021 3022 //--------------------------------------------------------------------------- 3023 3024 template<typename E1, typename E2> 3025 constexpr auto operator==(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3026 template<typename E1, typename E2> 3027 constexpr auto operator!=(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3028 template<typename E1, typename E2> 3029 constexpr auto operator>=(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3030 template<typename E1, typename E2> 3031 constexpr auto operator<=(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3032 template<typename E1, typename E2> 3033 constexpr auto operator>(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3034 template<typename E1, typename E2> 3035 constexpr auto operator<(const result<void, E1>& lhs, const result<void, E2>& rhs) noexcept -> bool; 3036 3037 //--------------------------------------------------------------------------- 3038 3039 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3040 constexpr auto operator==(const result<T, E>& exp, const U& value) noexcept -> bool; 3041 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3042 constexpr auto operator==(const T& value, const result<U, E>& exp) noexcept -> bool; 3043 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3044 constexpr auto operator!=(const result<T, E>& exp, const U& value) noexcept -> bool; 3045 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3046 constexpr auto operator!=(const T& value, const result<U, E>& exp) noexcept -> bool; 3047 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3048 constexpr auto operator<=(const result<T, E>& exp, const U& value) noexcept -> bool; 3049 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3050 constexpr auto operator<=(const T& value, const result<U, E>& exp) noexcept -> bool; 3051 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3052 constexpr auto operator>=(const result<T, E>& exp, const U& value) noexcept -> bool; 3053 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3054 constexpr auto operator>=(const T& value, const result<U, E>& exp) noexcept -> bool; 3055 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3056 constexpr auto operator<(const result<T, E>& exp, const U& value) noexcept -> bool; 3057 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3058 constexpr auto operator<(const T& value, const result<U, E>& exp) noexcept -> bool; 3059 template<typename T, typename E, typename U, typename = typename std::enable_if<!std::is_same<T, void>::value>::type> 3060 constexpr auto operator>(const result<T, E>& exp, const U& value) noexcept -> bool; 3061 template<typename T, typename U, typename E, typename = typename std::enable_if<!std::is_same<U, void>::value>::type> 3062 constexpr auto operator>(const T& value, const result<U, E>& exp) noexcept -> bool; 3063 3064 //--------------------------------------------------------------------------- 3065 3066 template<typename T, typename E, typename U> 3067 constexpr auto operator==(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3068 template<typename T, typename U, typename E> 3069 constexpr auto operator==(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3070 template<typename T, typename E, typename U> 3071 constexpr auto operator!=(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3072 template<typename T, typename U, typename E> 3073 constexpr auto operator!=(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3074 template<typename T, typename E, typename U> 3075 constexpr auto operator<=(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3076 template<typename T, typename U, typename E> 3077 constexpr auto operator<=(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3078 template<typename T, typename E, typename U> 3079 constexpr auto operator>=(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3080 template<typename T, typename U, typename E> 3081 constexpr auto operator>=(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3082 template<typename T, typename E, typename U> 3083 constexpr auto operator<(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3084 template<typename T, typename U, typename E> 3085 constexpr auto operator<(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3086 template<typename T, typename E, typename U> 3087 constexpr auto operator>(const result<T, E>& exp, const failure<U>& value) noexcept -> bool; 3088 template<typename T, typename U, typename E> 3089 constexpr auto operator>(const failure<T>& value, const result<E, U>& exp) noexcept -> bool; 3090 3091 //--------------------------------------------------------------------------- 3092 // Utilities 3093 //--------------------------------------------------------------------------- 3094 3095 /// \{ 3096 /// \brief Swaps the contents of \p lhs with \p rhs 3097 /// 3098 /// \param lhs the left result 3099 /// \param rhs the right result 3100 template<typename T, typename E> 3101 auto swap(result<T, E>& lhs, result<T, E>& rhs) 3102 #if __cplusplus >= 201703L 3103 noexcept( 3104 std::is_nothrow_move_constructible<result<T, E>>::value&& std::is_nothrow_move_assignable<result<T, E>>::value&& 3105 std::is_nothrow_swappable<T>::value&& std::is_nothrow_swappable<E>::value) 3106 #else 3107 noexcept( 3108 std::is_nothrow_move_constructible<result<T, E>>::value&& std::is_nothrow_move_assignable<result<T, E>>::value) 3109 #endif 3110 -> void; 3111 template<typename E> 3112 auto swap(result<void, E>& lhs, result<void, E>& rhs) 3113 #if __cplusplus >= 201703L 3114 noexcept(std::is_nothrow_move_constructible<result<void, E>>::value&& 3115 std::is_nothrow_move_assignable<result<void, E>>::value&& std::is_nothrow_swappable<E>::value) 3116 #else 3117 noexcept(std::is_nothrow_move_constructible<result<void, E>>::value&& 3118 std::is_nothrow_move_assignable<result<void, E>>::value) 3119 #endif 3120 -> void; 3121 /// \} 3122 3123 } // namespace bitwizeshift 3124 } // namespace RESULT_NAMESPACE_INTERNAL 3125 3126 namespace std { 3127 3128 template<typename T, typename E> 3129 struct hash<::RESULT_NS_IMPL::result<T, E>> { 3130 auto operator()(const RESULT_NS_IMPL::result<T, E>& x) const -> std::size_t 3131 { 3132 if (x.has_value()) { 3133 return std::hash<T>{}(*x) + 1; // add '1' to differentiate from error case 3134 } 3135 return std::hash<E>{}(::RESULT_NS_IMPL::detail::extract_error(x)); 3136 } 3137 }; 3138 3139 template<typename E> 3140 struct hash<::RESULT_NS_IMPL::result<void, E>> { 3141 auto operator()(const RESULT_NS_IMPL::result<void, E>& x) const -> std::size_t 3142 { 3143 if (x.has_value()) { 3144 return 0; 3145 } 3146 return std::hash<E>{}(::RESULT_NS_IMPL::detail::extract_error(x)); 3147 } 3148 }; 3149 3150 } // namespace std 3151 3152 #if !defined(RESULT_DISABLE_EXCEPTIONS) 3153 3154 //============================================================================= 3155 // class : bad_result_access 3156 //============================================================================= 3157 3158 //----------------------------------------------------------------------------- 3159 // Constructors 3160 //----------------------------------------------------------------------------- 3161 3162 template<typename E> 3163 template<typename E2, typename> 3164 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(E2&& error): 3165 logic_error{"error attempting to access value from result containing error"}, m_error(detail::forward<E2>(error)) 3166 { 3167 } 3168 3169 template<typename E> 3170 template<typename E2, typename> 3171 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(const char *what_arg, 3172 E2&& error): 3173 logic_error{what_arg}, m_error(detail::forward<E2>(error)) 3174 { 3175 } 3176 3177 template<typename E> 3178 template<typename E2, typename> 3179 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(const std::string& what_arg, 3180 E2&& error): 3181 logic_error{what_arg}, m_error(detail::forward<E2>(error)) 3182 { 3183 } 3184 3185 //----------------------------------------------------------------------------- 3186 // Observers 3187 //----------------------------------------------------------------------------- 3188 3189 template<typename E> 3190 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::bad_result_access<E>::error() & noexcept -> E& 3191 { 3192 return m_error; 3193 } 3194 3195 template<typename E> 3196 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::bad_result_access<E>::error() && noexcept -> E&& 3197 { 3198 return static_cast<E&&>(m_error); 3199 } 3200 3201 template<typename E> 3202 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::bad_result_access<E>::error() const& noexcept -> const E& 3203 { 3204 return m_error; 3205 } 3206 3207 template<typename E> 3208 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::bad_result_access<E>::error() const&& noexcept -> const E&& 3209 { 3210 return static_cast<const E&&>(m_error); 3211 } 3212 3213 #endif 3214 3215 //============================================================================= 3216 // class : failure 3217 //============================================================================= 3218 3219 //----------------------------------------------------------------------------- 3220 // Constructors 3221 //----------------------------------------------------------------------------- 3222 3223 template<typename E> 3224 template<typename... Args, typename> 3225 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure(in_place_t, Args&&...args) noexcept( 3226 std::is_nothrow_constructible<E, Args...>::value): 3227 m_failure(detail::forward<Args>(args)...) 3228 { 3229 } 3230 3231 template<typename E> 3232 template<typename U, typename... Args, typename> 3233 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure( 3234 in_place_t, 3235 std::initializer_list<U> ilist, 3236 Args&&...args) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value): 3237 m_failure(ilist, detail::forward<Args>(args)...) 3238 { 3239 } 3240 3241 template<typename E> 3242 template< 3243 typename E2, 3244 typename std::enable_if<RESULT_NS_IMPL::detail::failure_is_explicit_value_convertible<E, E2>::value, int>::type> 3245 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure(E2&& error) noexcept( 3246 std::is_nothrow_constructible<E, E2>::value): 3247 m_failure(detail::forward<E2>(error)) 3248 { 3249 } 3250 3251 template<typename E> 3252 template< 3253 typename E2, 3254 typename std::enable_if<RESULT_NS_IMPL::detail::failure_is_implicit_value_convertible<E, E2>::value, int>::type> 3255 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure(E2&& error) noexcept( 3256 std::is_nothrow_constructible<E, E2>::value): 3257 m_failure(detail::forward<E2>(error)) 3258 { 3259 } 3260 3261 template<typename E> 3262 template<typename E2, typename> 3263 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure(const failure<E2>& other) noexcept( 3264 std::is_nothrow_constructible<E, const E2&>::value): 3265 m_failure(other.error()) 3266 { 3267 } 3268 3269 template<typename E> 3270 template<typename E2, typename> 3271 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::failure<E>::failure(failure<E2>&& other) noexcept( 3272 std::is_nothrow_constructible<E, E2&&>::value): 3273 m_failure(static_cast<failure<E2>&&>(other).error()) 3274 { 3275 } 3276 3277 //----------------------------------------------------------------------------- 3278 3279 template<typename E> 3280 template<typename E2, typename> 3281 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 3282 RESULT_NS_IMPL::failure<E>::operator=(E2&& error) noexcept(std::is_nothrow_assignable<E, E2>::value 3283 || std::is_lvalue_reference<E>::value) -> failure& 3284 { 3285 m_failure = detail::forward<E2>(error); 3286 3287 return (*this); 3288 } 3289 3290 template<typename E> 3291 template<typename E2, typename> 3292 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::failure<E>::operator=( 3293 const failure<E2>& other) noexcept(std::is_nothrow_assignable<E, const E2&>::value) -> failure& 3294 { 3295 m_failure = other.error(); 3296 3297 return (*this); 3298 } 3299 3300 template<typename E> 3301 template<typename E2, typename> 3302 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 3303 RESULT_NS_IMPL::failure<E>::operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) 3304 -> failure& 3305 { 3306 m_failure = static_cast<failure<E2>&&>(other).error(); 3307 3308 return (*this); 3309 } 3310 3311 //----------------------------------------------------------------------------- 3312 // Observers 3313 //----------------------------------------------------------------------------- 3314 3315 template<typename E> 3316 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::failure<E>::error() & noexcept -> 3317 typename std::add_lvalue_reference<E>::type 3318 { 3319 return m_failure; 3320 } 3321 3322 template<typename E> 3323 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::failure<E>::error() && noexcept -> 3324 typename std::add_rvalue_reference<E>::type 3325 { 3326 using reference = typename std::add_rvalue_reference<E>::type; 3327 3328 return static_cast<reference>(m_failure); 3329 } 3330 3331 template<typename E> 3332 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::failure<E>::error() const& noexcept -> 3333 typename std::add_lvalue_reference<typename std::add_const<E>::type>::type 3334 { 3335 return m_failure; 3336 } 3337 3338 template<typename E> 3339 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::failure<E>::error() const&& noexcept -> 3340 typename std::add_rvalue_reference<typename std::add_const<E>::type>::type 3341 { 3342 using reference = typename std::add_rvalue_reference<typename std::add_const<E>::type>::type; 3343 3344 return static_cast<reference>(m_failure); 3345 } 3346 3347 //============================================================================= 3348 // non-member functions : class : failure 3349 //============================================================================= 3350 3351 //----------------------------------------------------------------------------- 3352 // Comparison 3353 //----------------------------------------------------------------------------- 3354 3355 template<typename E1, typename E2> 3356 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const failure<E1>& lhs, 3357 const failure<E2>& rhs) noexcept -> bool 3358 { 3359 return lhs.error() == rhs.error(); 3360 } 3361 3362 template<typename E1, typename E2> 3363 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const failure<E1>& lhs, 3364 const failure<E2>& rhs) noexcept -> bool 3365 { 3366 return lhs.error() != rhs.error(); 3367 } 3368 3369 template<typename E1, typename E2> 3370 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const failure<E1>& lhs, 3371 const failure<E2>& rhs) noexcept -> bool 3372 { 3373 return lhs.error() < rhs.error(); 3374 } 3375 3376 template<typename E1, typename E2> 3377 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const failure<E1>& lhs, 3378 const failure<E2>& rhs) noexcept -> bool 3379 { 3380 return lhs.error() > rhs.error(); 3381 } 3382 3383 template<typename E1, typename E2> 3384 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const failure<E1>& lhs, 3385 const failure<E2>& rhs) noexcept -> bool 3386 { 3387 return lhs.error() <= rhs.error(); 3388 } 3389 3390 template<typename E1, typename E2> 3391 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const failure<E1>& lhs, 3392 const failure<E2>& rhs) noexcept -> bool 3393 { 3394 return lhs.error() >= rhs.error(); 3395 } 3396 3397 //----------------------------------------------------------------------------- 3398 // Utilities 3399 //----------------------------------------------------------------------------- 3400 3401 template<typename E> 3402 inline RESULT_INLINE_VISIBILITY constexpr auto 3403 RESULT_NS_IMPL::fail(E&& e) noexcept(std::is_nothrow_constructible<typename std::decay<E>::type, E>::value) 3404 -> failure<typename std::decay<E>::type> 3405 { 3406 using result_type = failure<typename std::decay<E>::type>; 3407 3408 return result_type(detail::forward<E>(e)); 3409 } 3410 3411 template<typename E> 3412 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::fail(std::reference_wrapper<E> e) noexcept -> failure<E&> 3413 { 3414 using result_type = failure<E&>; 3415 3416 return result_type{e.get()}; 3417 } 3418 3419 template<typename E, typename... Args, typename> 3420 inline RESULT_INLINE_VISIBILITY constexpr auto 3421 RESULT_NS_IMPL::fail(Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value) -> failure<E> 3422 { 3423 return failure<E>(in_place, detail::forward<Args>(args)...); 3424 } 3425 3426 template<typename E, typename U, typename... Args, typename> 3427 inline RESULT_INLINE_VISIBILITY constexpr auto 3428 RESULT_NS_IMPL::fail(std::initializer_list<U> ilist, 3429 Args&&...args) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value) 3430 -> failure<E> 3431 { 3432 return failure<E>(in_place, ilist, detail::forward<Args>(args)...); 3433 } 3434 3435 template<typename E> 3436 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::swap(failure<E>& lhs, failure<E>& rhs) 3437 #if __cplusplus >= 201703L 3438 noexcept(std::is_nothrow_swappable<E>::value) -> void 3439 #else 3440 noexcept(std::is_nothrow_move_constructible<E>::value) -> void 3441 #endif 3442 { 3443 using std::swap; 3444 3445 swap(lhs.error(), rhs.error()); 3446 } 3447 3448 //============================================================================= 3449 // class : detail::result_union<T, E, IsTrivial> 3450 //============================================================================= 3451 3452 //----------------------------------------------------------------------------- 3453 // Constructors / Assignment 3454 //----------------------------------------------------------------------------- 3455 3456 template<typename T, typename E, bool IsTrivial> 3457 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>::result_union(unit) noexcept: 3458 m_empty{} 3459 { 3460 // m_has_value intentionally not set 3461 } 3462 3463 template<typename T, typename E, bool IsTrivial> 3464 template<typename... Args> 3465 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>::result_union( 3466 in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value): 3467 m_value(detail::forward<Args>(args)...), m_has_value{true} 3468 { 3469 } 3470 3471 template<typename T, typename E, bool IsTrivial> 3472 template<typename... Args> 3473 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>::result_union( 3474 in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value): 3475 m_error(detail::forward<Args>(args)...), m_has_value{false} 3476 { 3477 } 3478 3479 //----------------------------------------------------------------------------- 3480 // Modifiers 3481 //----------------------------------------------------------------------------- 3482 3483 template<typename T, typename E, bool IsTrivial> 3484 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_union<T, E, IsTrivial>::destroy() const noexcept 3485 -> void 3486 { 3487 // do nothing 3488 } 3489 3490 //============================================================================= 3491 // class : detail::result_union<T, E, false> 3492 //============================================================================= 3493 3494 //----------------------------------------------------------------------------- 3495 // Constructors / Destructor / Assignment 3496 //----------------------------------------------------------------------------- 3497 3498 template<typename T, typename E> 3499 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::detail::result_union<T, E, false>::result_union(unit) noexcept: 3500 m_empty{} 3501 { 3502 // m_has_value intentionally not set 3503 } 3504 3505 template<typename T, typename E> 3506 template<typename... Args> 3507 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::detail::result_union<T, E, false>::result_union( 3508 in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value): 3509 m_value(detail::forward<Args>(args)...), m_has_value{true} 3510 { 3511 } 3512 3513 template<typename T, typename E> 3514 template<typename... Args> 3515 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::detail::result_union<T, E, false>::result_union( 3516 in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value): 3517 m_error(detail::forward<Args>(args)...), m_has_value{false} 3518 { 3519 } 3520 3521 //----------------------------------------------------------------------------- 3522 3523 #if __cplusplus >= 202002L 3524 template<typename T, typename E> 3525 inline RESULT_INLINE_VISIBILITY 3526 RESULT_NS_IMPL::detail::result_union<T, E, false>::result_union::~result_union() noexcept( 3527 std::is_nothrow_destructible<T>::value&& std::is_nothrow_destructible<E>::value) 3528 { 3529 destroy(); 3530 } 3531 #else 3532 template<typename T, typename E> 3533 inline RESULT_INLINE_VISIBILITY 3534 RESULT_NS_IMPL::detail::result_union<T, E, false>::~result_union<T, E, false>() noexcept( 3535 std::is_nothrow_destructible<T>::value&& std::is_nothrow_destructible<E>::value) 3536 { 3537 destroy(); 3538 } 3539 #endif 3540 3541 //----------------------------------------------------------------------------- 3542 // Modifiers 3543 //----------------------------------------------------------------------------- 3544 3545 template<typename T, typename E> 3546 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_union<T, E, false>::destroy() -> void 3547 { 3548 if (m_has_value) { 3549 m_value.~underlying_value_type(); 3550 } else { 3551 m_error.~underlying_error_type(); 3552 } 3553 } 3554 3555 //============================================================================= 3556 // class : result_construct_base<T, E> 3557 //============================================================================= 3558 3559 //----------------------------------------------------------------------------- 3560 // Constructors / Assignment 3561 //----------------------------------------------------------------------------- 3562 3563 template<typename T, typename E> 3564 inline RESULT_INLINE_VISIBILITY 3565 RESULT_NS_IMPL::detail::result_construct_base<T, E>::result_construct_base(unit) noexcept: 3566 storage{unit{}} 3567 { 3568 } 3569 3570 template<typename T, typename E> 3571 template<typename... Args> 3572 inline constexpr RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::detail::result_construct_base<T, E>::result_construct_base( 3573 in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value): 3574 storage{in_place, detail::forward<Args>(args)...} 3575 { 3576 } 3577 3578 template<typename T, typename E> 3579 template<typename... Args> 3580 inline constexpr RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::detail::result_construct_base<T, E>::result_construct_base( 3581 in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value): 3582 storage(in_place_error, detail::forward<Args>(args)...) 3583 { 3584 } 3585 3586 //----------------------------------------------------------------------------- 3587 // Construction / Assignment 3588 //----------------------------------------------------------------------------- 3589 3590 template<typename T, typename E> 3591 template<typename... Args> 3592 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_value( 3593 Args&&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> void 3594 { 3595 using value_type = typename storage_type::underlying_value_type; 3596 3597 auto *p = static_cast<void *>(std::addressof(storage.m_value)); 3598 new (p) value_type(detail::forward<Args>(args)...); 3599 storage.m_has_value = true; 3600 } 3601 3602 template<typename T, typename E> 3603 template<typename... Args> 3604 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_error( 3605 Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value) -> void 3606 { 3607 using error_type = typename storage_type::underlying_error_type; 3608 3609 auto *p = static_cast<void *>(std::addressof(storage.m_error)); 3610 new (p) error_type(detail::forward<Args>(args)...); 3611 storage.m_has_value = false; 3612 } 3613 3614 template<typename T, typename E> 3615 template<typename Result> 3616 inline RESULT_INLINE_VISIBILITY auto 3617 RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_error_from_result(Result&& other) -> void 3618 { 3619 if (other.storage.m_has_value) { 3620 construct_value(); 3621 } else { 3622 construct_error(detail::forward<Result>(other).storage.m_error); 3623 } 3624 } 3625 3626 template<typename T, typename E> 3627 template<typename Result> 3628 inline RESULT_INLINE_VISIBILITY auto 3629 RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_from_result(Result&& other) -> void 3630 { 3631 if (other.storage.m_has_value) { 3632 construct_value_from_result_impl(std::is_lvalue_reference<T>{}, detail::forward<Result>(other).storage.m_value); 3633 } else { 3634 construct_error(detail::forward<Result>(other).storage.m_error); 3635 } 3636 } 3637 3638 template<typename T, typename E> 3639 template<typename Value> 3640 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_construct_base<T, E>::assign_value( 3641 Value&& value) noexcept(std::is_nothrow_assignable<T, Value>::value) -> void 3642 { 3643 if (!storage.m_has_value) { 3644 storage.destroy(); 3645 construct_value(detail::forward<Value>(value)); 3646 } else { 3647 storage.m_value = detail::forward<Value>(value); 3648 } 3649 } 3650 3651 template<typename T, typename E> 3652 template<typename Error> 3653 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_construct_base<T, E>::assign_error( 3654 Error&& error) noexcept(std::is_nothrow_assignable<E, Error>::value) -> void 3655 { 3656 if (storage.m_has_value) { 3657 storage.destroy(); 3658 construct_error(detail::forward<Error>(error)); 3659 } else { 3660 storage.m_error = detail::forward<Error>(error); 3661 } 3662 } 3663 3664 template<typename T, typename E> 3665 template<typename Result> 3666 inline RESULT_INLINE_VISIBILITY auto 3667 RESULT_NS_IMPL::detail::result_construct_base<T, E>::assign_from_result(Result&& other) -> void 3668 { 3669 if (other.storage.m_has_value != storage.m_has_value) { 3670 storage.destroy(); 3671 construct_from_result(detail::forward<Result>(other)); 3672 } else if (storage.m_has_value) { 3673 assign_value_from_result_impl(std::is_lvalue_reference<T>{}, detail::forward<Result>(other)); 3674 } else { 3675 storage.m_error = detail::forward<Result>(other).storage.m_error; 3676 } 3677 } 3678 3679 template<typename T, typename E> 3680 template<typename ReferenceWrapper> 3681 inline RESULT_INLINE_VISIBILITY auto 3682 RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_value_from_result_impl( 3683 std::true_type, ReferenceWrapper&& reference) noexcept -> void 3684 { 3685 using value_type = typename storage_type::underlying_value_type; 3686 3687 auto *p = static_cast<void *>(std::addressof(storage.m_value)); 3688 new (p) value_type(reference.get()); 3689 storage.m_has_value = true; 3690 } 3691 3692 template<typename T, typename E> 3693 template<typename Value> 3694 inline RESULT_INLINE_VISIBILITY auto 3695 RESULT_NS_IMPL::detail::result_construct_base<T, E>::construct_value_from_result_impl( 3696 std::false_type, Value&& value) noexcept(std::is_nothrow_constructible<T, Value>::value) -> void 3697 { 3698 using value_type = typename storage_type::underlying_value_type; 3699 3700 auto *p = static_cast<void *>(std::addressof(storage.m_value)); 3701 new (p) value_type(detail::forward<Value>(value)); 3702 storage.m_has_value = true; 3703 } 3704 3705 template<typename T, typename E> 3706 template<typename Result> 3707 inline RESULT_INLINE_VISIBILITY auto 3708 RESULT_NS_IMPL::detail::result_construct_base<T, E>::assign_value_from_result_impl(std::true_type, Result&& other) 3709 -> void 3710 { 3711 // T is a reference; unwrap it 3712 storage.m_value = other.storage.m_value.get(); 3713 } 3714 3715 template<typename T, typename E> 3716 template<typename Result> 3717 inline RESULT_INLINE_VISIBILITY auto 3718 RESULT_NS_IMPL::detail::result_construct_base<T, E>::assign_value_from_result_impl(std::false_type, Result&& other) 3719 -> void 3720 { 3721 storage.m_value = detail::forward<Result>(other).storage.m_value; 3722 } 3723 3724 //============================================================================= 3725 // class : result_trivial_copy_ctor_base_impl 3726 //============================================================================= 3727 3728 template<typename T, typename E> 3729 inline RESULT_INLINE_VISIBILITY 3730 RESULT_NS_IMPL::detail::result_trivial_copy_ctor_base_impl<T, E>::result_trivial_copy_ctor_base_impl( 3731 const result_trivial_copy_ctor_base_impl& 3732 other) noexcept(std::is_nothrow_copy_constructible<T>::value&& std::is_nothrow_copy_constructible<E>::value): 3733 base_type(unit{}) 3734 { 3735 using ctor_base = result_construct_base<T, E>; 3736 3737 ctor_base::construct_from_result(static_cast<const ctor_base&>(other)); 3738 } 3739 3740 //============================================================================= 3741 // class : result_trivial_move_ctor_base 3742 //============================================================================= 3743 3744 template<typename T, typename E> 3745 inline RESULT_INLINE_VISIBILITY 3746 RESULT_NS_IMPL::detail::result_trivial_move_ctor_base_impl<T, E>::result_trivial_move_ctor_base_impl( 3747 result_trivial_move_ctor_base_impl&& 3748 other) noexcept(std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_constructible<E>::value): 3749 base_type(unit{}) 3750 { 3751 using ctor_base = result_construct_base<T, E>; 3752 3753 ctor_base::construct_from_result(static_cast<ctor_base&&>(other)); 3754 } 3755 3756 //============================================================================= 3757 // class : result_copy_assign_base 3758 //============================================================================= 3759 3760 template<typename T, typename E> 3761 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_trivial_copy_assign_base_impl<T, E>::operator=( 3762 const result_trivial_copy_assign_base_impl& 3763 other) noexcept(std::is_nothrow_copy_constructible<T>::value&& std::is_nothrow_copy_constructible<E>::value&& 3764 std::is_nothrow_copy_assignable<T>::value&& std::is_nothrow_copy_assignable<E>::value) 3765 -> result_trivial_copy_assign_base_impl& 3766 { 3767 using ctor_base = result_construct_base<T, E>; 3768 3769 ctor_base::assign_from_result(static_cast<const ctor_base&>(other)); 3770 return (*this); 3771 } 3772 3773 //========================================================================= 3774 // class : result_move_assign_base 3775 //========================================================================= 3776 3777 template<typename T, typename E> 3778 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::result_trivial_move_assign_base_impl<T, E>::operator=( 3779 result_trivial_move_assign_base_impl&& 3780 other) noexcept(std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_constructible<E>::value&& 3781 std::is_nothrow_move_assignable<T>::value&& std::is_nothrow_move_assignable<E>::value) 3782 -> result_trivial_move_assign_base_impl& 3783 { 3784 using ctor_base = result_construct_base<T, E>; 3785 3786 ctor_base::assign_from_result(static_cast<ctor_base&&>(other)); 3787 return (*this); 3788 } 3789 3790 template<typename T, typename E> 3791 inline RESULT_INLINE_VISIBILITY constexpr auto 3792 RESULT_NS_IMPL::detail::result_error_extractor::get(const result<T, E>& exp) noexcept -> const E& 3793 { 3794 return exp.m_storage.storage.m_error; 3795 } 3796 3797 template<typename T, typename E> 3798 inline RESULT_INLINE_VISIBILITY constexpr auto 3799 RESULT_NS_IMPL::detail::result_error_extractor::get(result<T, E>& exp) noexcept -> E& 3800 { 3801 return exp.m_storage.storage.m_error; 3802 } 3803 3804 template<typename T, typename E> 3805 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::detail::extract_error(const result<T, E>& exp) noexcept 3806 -> const E& 3807 { 3808 return result_error_extractor::get(exp); 3809 } 3810 3811 template<typename E> 3812 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::throw_bad_result_access(E&& error) -> void 3813 { 3814 #if defined(RESULT_DISABLE_EXCEPTIONS) 3815 std::fprintf(stderr, "error attempting to access value from result containing error\n"); 3816 std::abort(); 3817 #else 3818 using exception_type = bad_result_access<typename std::remove_const<typename std::remove_reference<E>::type>::type>; 3819 3820 throw exception_type{detail::forward<E>(error)}; 3821 #endif 3822 } 3823 3824 template<typename String, typename E> 3825 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::detail::throw_bad_result_access_message(String&& message, 3826 E&& error) -> void 3827 { 3828 #if defined(RESULT_DISABLE_EXCEPTIONS) 3829 const auto message_string = std::string{detail::forward<String>(message)}; 3830 std::fprintf(stderr, "%s\n", message_string.c_str()); 3831 std::abort(); 3832 #else 3833 using exception_type = bad_result_access<typename std::remove_const<typename std::remove_reference<E>::type>::type>; 3834 3835 throw exception_type{detail::forward<String>(message), detail::forward<E>(error)}; 3836 #endif 3837 } 3838 3839 //============================================================================= 3840 // class : result<T,E> 3841 //============================================================================= 3842 3843 template<typename T, typename E> 3844 template<typename U, typename> 3845 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result() noexcept( 3846 std::is_nothrow_constructible<U>::value): 3847 m_storage(in_place) 3848 { 3849 } 3850 3851 template<typename T, typename E> 3852 template<typename T2, 3853 typename E2, 3854 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_copy_convertible<T, E, T2, E2>::value, 3855 int>::type> 3856 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::result<T, E>::result(const result<T2, E2>& other) noexcept( 3857 std::is_nothrow_constructible<T, const T2&>::value&& std::is_nothrow_constructible<E, const E2&>::value): 3858 m_storage(detail::unit{}) 3859 { 3860 m_storage.construct_from_result(static_cast<const result<T2, E2>&>(other).m_storage); 3861 } 3862 3863 template<typename T, typename E> 3864 template<typename T2, 3865 typename E2, 3866 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_copy_convertible<T, E, T2, E2>::value, 3867 int>::type> 3868 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::result<T, E>::result(const result<T2, E2>& other) noexcept( 3869 std::is_nothrow_constructible<T, const T2&>::value&& std::is_nothrow_constructible<E, const E2&>::value): 3870 m_storage(detail::unit{}) 3871 { 3872 m_storage.construct_from_result(static_cast<const result<T2, E2>&>(other).m_storage); 3873 } 3874 3875 template<typename T, typename E> 3876 template<typename T2, 3877 typename E2, 3878 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_move_convertible<T, E, T2, E2>::value, 3879 int>::type> 3880 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::result<T, E>::result(result<T2, E2>&& other) noexcept( 3881 std::is_nothrow_constructible<T, T2&&>::value&& std::is_nothrow_constructible<E, E2&&>::value): 3882 m_storage(detail::unit{}) 3883 { 3884 m_storage.construct_from_result(static_cast<result<T2, E2>&&>(other).m_storage); 3885 } 3886 3887 template<typename T, typename E> 3888 template<typename T2, 3889 typename E2, 3890 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_move_convertible<T, E, T2, E2>::value, 3891 int>::type> 3892 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::result<T, E>::result(result<T2, E2>&& other) noexcept( 3893 std::is_nothrow_constructible<T, T2&&>::value&& std::is_nothrow_constructible<E, E2&&>::value): 3894 m_storage(detail::unit{}) 3895 { 3896 m_storage.construct_from_result(static_cast<result<T2, E2>&&>(other).m_storage); 3897 } 3898 3899 //----------------------------------------------------------------------------- 3900 3901 template<typename T, typename E> 3902 template<typename... Args, typename> 3903 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result(in_place_t, Args&&...args) noexcept( 3904 std::is_nothrow_constructible<T, Args...>::value): 3905 m_storage(in_place, detail::forward<Args>(args)...) 3906 { 3907 } 3908 3909 template<typename T, typename E> 3910 template<typename U, typename... Args, typename> 3911 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result( 3912 in_place_t, 3913 std::initializer_list<U> ilist, 3914 Args&&...args) noexcept(std::is_nothrow_constructible<T, std::initializer_list<U>, Args...>::value): 3915 m_storage(in_place, ilist, detail::forward<Args>(args)...) 3916 { 3917 } 3918 3919 //----------------------------------------------------------------------------- 3920 3921 template<typename T, typename E> 3922 template<typename... Args, typename> 3923 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result( 3924 in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value): 3925 m_storage(in_place_error, detail::forward<Args>(args)...) 3926 { 3927 } 3928 3929 template<typename T, typename E> 3930 template<typename U, typename... Args, typename> 3931 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result( 3932 in_place_error_t, 3933 std::initializer_list<U> ilist, 3934 Args&&...args) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value): 3935 m_storage(in_place_error, ilist, detail::forward<Args>(args)...) 3936 { 3937 } 3938 3939 //------------------------------------------------------------------------- 3940 3941 template<typename T, typename E> 3942 template<typename E2, typename> 3943 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result(const failure<E2>& e) noexcept( 3944 std::is_nothrow_constructible<E, const E2&>::value): 3945 m_storage(in_place_error, e.error()) 3946 { 3947 } 3948 3949 template<typename T, typename E> 3950 template<typename E2, typename> 3951 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result(failure<E2>&& e) noexcept( 3952 std::is_nothrow_constructible<E, E2&&>::value): 3953 m_storage(in_place_error, static_cast<E2&&>(e.error())) 3954 { 3955 } 3956 3957 template<typename T, typename E> 3958 template<typename U, 3959 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_explicit_value_convertible<T, U>::value, int>::type> 3960 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result(U&& value) noexcept( 3961 std::is_nothrow_constructible<T, U>::value): 3962 m_storage(in_place, detail::forward<U>(value)) 3963 { 3964 } 3965 3966 template<typename T, typename E> 3967 template<typename U, 3968 typename std::enable_if<RESULT_NS_IMPL::detail::result_is_implicit_value_convertible<T, U>::value, int>::type> 3969 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::result(U&& value) noexcept( 3970 std::is_nothrow_constructible<T, U>::value): 3971 m_storage(in_place, detail::forward<U>(value)) 3972 { 3973 } 3974 3975 //----------------------------------------------------------------------------- 3976 3977 template<typename T, typename E> 3978 template<typename T2, typename E2, typename> 3979 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<T, E>::operator=(const result<T2, E2>& other) noexcept( 3980 std::is_nothrow_assignable<T, const T2&>::value&& std::is_nothrow_assignable<E, const E2&>::value) -> result& 3981 { 3982 m_storage.assign_from_result(static_cast<const result<T2, E2>&>(other).m_storage); 3983 return (*this); 3984 } 3985 3986 template<typename T, typename E> 3987 template<typename T2, typename E2, typename> 3988 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<T, E>::operator=(result<T2, E2>&& other) noexcept( 3989 std::is_nothrow_assignable<T, T2&&>::value&& std::is_nothrow_assignable<E, E2&&>::value) -> result& 3990 { 3991 m_storage.assign_from_result(static_cast<result<T2, E2>&&>(other).m_storage); 3992 return (*this); 3993 } 3994 3995 template<typename T, typename E> 3996 template<typename U, typename> 3997 inline RESULT_INLINE_VISIBILITY auto 3998 RESULT_NS_IMPL::result<T, E>::operator=(U&& value) noexcept(std::is_nothrow_assignable<T, U>::value) -> result& 3999 { 4000 m_storage.assign_value(detail::forward<U>(value)); 4001 return (*this); 4002 } 4003 4004 template<typename T, typename E> 4005 template<typename E2, typename> 4006 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<T, E>::operator=(const failure<E2>& other) noexcept( 4007 std::is_nothrow_assignable<E, const E2&>::value) -> result& 4008 { 4009 m_storage.assign_error(other.error()); 4010 return (*this); 4011 } 4012 4013 template<typename T, typename E> 4014 template<typename E2, typename> 4015 inline RESULT_INLINE_VISIBILITY auto 4016 RESULT_NS_IMPL::result<T, E>::operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) 4017 -> result& 4018 { 4019 m_storage.assign_error(static_cast<E2&&>(other.error())); 4020 return (*this); 4021 } 4022 4023 //----------------------------------------------------------------------------- 4024 // Observers 4025 //----------------------------------------------------------------------------- 4026 4027 template<typename T, typename E> 4028 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::operator->() noexcept -> 4029 typename std::remove_reference<T>::type * 4030 { 4031 // Prior to C++17, std::addressof was not `constexpr`. 4032 // Since `addressof` fixes a relatively obscure issue where users define a 4033 // custom `operator&`, the pre-C++17 implementation has been defined to be 4034 // `&(**this)` so that it may exist in constexpr contexts. 4035 #if __cplusplus >= 201703L 4036 return std::addressof(**this); 4037 #else 4038 return &(**this); 4039 #endif 4040 } 4041 4042 template<typename T, typename E> 4043 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::operator->() const noexcept -> 4044 typename std::remove_reference<typename std::add_const<T>::type>::type * 4045 { 4046 #if __cplusplus >= 201703L 4047 return std::addressof(**this); 4048 #else 4049 return &(**this); 4050 #endif 4051 } 4052 4053 template<typename T, typename E> 4054 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::operator*() & noexcept -> 4055 typename std::add_lvalue_reference<T>::type 4056 { 4057 return m_storage.storage.m_value; 4058 } 4059 4060 template<typename T, typename E> 4061 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::operator*() && noexcept -> 4062 typename std::add_rvalue_reference<T>::type 4063 { 4064 using reference = typename std::add_rvalue_reference<T>::type; 4065 4066 return static_cast<reference>(m_storage.storage.m_value); 4067 } 4068 4069 template<typename T, typename E> 4070 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::operator*() const& noexcept -> 4071 typename std::add_lvalue_reference<typename std::add_const<T>::type>::type 4072 { 4073 return m_storage.storage.m_value; 4074 } 4075 4076 template<typename T, typename E> 4077 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::operator*() const&& noexcept -> 4078 typename std::add_rvalue_reference<typename std::add_const<T>::type>::type 4079 { 4080 using reference = typename std::add_rvalue_reference<typename std::add_const<T>::type>::type; 4081 4082 return static_cast<reference>(m_storage.storage.m_value); 4083 } 4084 4085 //----------------------------------------------------------------------------- 4086 4087 template<typename T, typename E> 4088 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<T, E>::operator bool() const noexcept 4089 { 4090 return m_storage.storage.m_has_value; 4091 } 4092 4093 template<typename T, typename E> 4094 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::has_value() const noexcept -> bool 4095 { 4096 return m_storage.storage.m_has_value; 4097 } 4098 4099 template<typename T, typename E> 4100 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::has_error() const noexcept -> bool 4101 { 4102 return !m_storage.storage.m_has_value; 4103 } 4104 4105 //----------------------------------------------------------------------------- 4106 4107 // The `has_value()` expression below is incorrectly identified as an unused 4108 // value, which results in the `-Wunused-value` warning. This is suppressed 4109 // to prevent false-positives 4110 #if defined(__clang__) 4111 #pragma clang diagnostic push 4112 #pragma clang diagnostic ignored "-Wunused-value" 4113 #elif defined(__GNUC__) 4114 #pragma GCC diagnostic push 4115 #pragma GCC diagnostic ignored "-Wunused-value" 4116 #elif defined(_MSC_VER) 4117 // Older MSVC versions incorrectly warn on returning a reference to a temporary. 4118 // This has been suppressed 4119 #pragma warning(push) 4120 #pragma warning(disable : 4172) 4121 #endif 4122 4123 template<typename T, typename E> 4124 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::value() & -> 4125 typename std::add_lvalue_reference<T>::type 4126 { 4127 return (has_value() || (detail::throw_bad_result_access(m_storage.storage.m_error), false), 4128 m_storage.storage.m_value); 4129 } 4130 4131 template<typename T, typename E> 4132 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::value() && -> 4133 typename std::add_rvalue_reference<T>::type 4134 { 4135 using reference = typename std::add_rvalue_reference<T>::type; 4136 4137 return (has_value() || (detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true), 4138 static_cast<reference>(m_storage.storage.m_value)); 4139 } 4140 4141 template<typename T, typename E> 4142 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::value() const& -> 4143 typename std::add_lvalue_reference<typename std::add_const<T>::type>::type 4144 { 4145 return (has_value() || (detail::throw_bad_result_access(m_storage.storage.m_error), true), 4146 m_storage.storage.m_value); 4147 } 4148 4149 template<typename T, typename E> 4150 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::value() const&& -> 4151 typename std::add_rvalue_reference<typename std::add_const<T>::type>::type 4152 { 4153 using reference = typename std::add_rvalue_reference<typename std::add_const<T>::type>::type; 4154 4155 return (has_value() || (detail::throw_bad_result_access(static_cast<const E&&>(m_storage.storage.m_error)), true), 4156 (static_cast<reference>(m_storage.storage.m_value))); 4157 } 4158 4159 #if defined(__clang__) 4160 #pragma clang diagnostic pop 4161 #elif defined(__GNUC__) 4162 #pragma GCC diagnostic pop 4163 #elif defined(_MSC_VER) 4164 #pragma warning(pop) 4165 #endif 4166 4167 template<typename T, typename E> 4168 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::error() const& noexcept( 4169 std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) -> E 4170 { 4171 static_assert(std::is_default_constructible<E>::value, 4172 "E must be default-constructible if 'error()' checks are used. " 4173 "This is to allow for default-constructed error states to represent the " 4174 "'good' state"); 4175 4176 return m_storage.storage.m_has_value ? E{} : m_storage.storage.m_error; 4177 } 4178 4179 template<typename T, typename E> 4180 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::error() && noexcept( 4181 std::is_nothrow_constructible<E>::value&& std::is_nothrow_move_constructible<E>::value) -> E 4182 { 4183 static_assert(std::is_default_constructible<E>::value, 4184 "E must be default-constructible if 'error()' checks are used. " 4185 "This is to allow for default-constructed error states to represent the " 4186 "'good' state"); 4187 4188 return m_storage.storage.m_has_value ? E{} : static_cast<E&&>(m_storage.storage.m_error); 4189 } 4190 4191 //----------------------------------------------------------------------------- 4192 4193 template<typename T, typename E> 4194 template<typename String, typename> 4195 inline RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::expect(String&& message) const& -> void 4196 { 4197 if (has_error()) { 4198 detail::throw_bad_result_access_message(detail::forward<String>(message), m_storage.storage.m_error); 4199 } 4200 } 4201 4202 template<typename T, typename E> 4203 template<typename String, typename> 4204 inline RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<T, E>::expect(String&& message) && -> void 4205 { 4206 if (has_error()) { 4207 detail::throw_bad_result_access_message(detail::forward<String>(message), 4208 static_cast<E&&>(m_storage.storage.m_error)); 4209 } 4210 } 4211 4212 //----------------------------------------------------------------------------- 4213 // Monadic Functionalities 4214 //----------------------------------------------------------------------------- 4215 4216 template<typename T, typename E> 4217 template<typename U> 4218 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::value_or(U&& default_value) const& -> 4219 typename std::remove_reference<T>::type 4220 { 4221 return m_storage.storage.m_has_value ? m_storage.storage.m_value : detail::forward<U>(default_value); 4222 } 4223 4224 template<typename T, typename E> 4225 template<typename U> 4226 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4227 RESULT_NS_IMPL::result<T, E>::value_or(U&& default_value) && -> typename std::remove_reference<T>::type 4228 { 4229 return m_storage.storage.m_has_value ? static_cast<T&&>(**this) : detail::forward<U>(default_value); 4230 } 4231 4232 template<typename T, typename E> 4233 template<typename U> 4234 inline RESULT_INLINE_VISIBILITY constexpr auto 4235 RESULT_NS_IMPL::result<T, E>::error_or(U&& default_error) const& -> error_type 4236 { 4237 return m_storage.storage.m_has_value ? detail::forward<U>(default_error) : m_storage.storage.m_error; 4238 } 4239 4240 template<typename T, typename E> 4241 template<typename U> 4242 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4243 RESULT_NS_IMPL::result<T, E>::error_or(U&& default_error) && -> error_type 4244 { 4245 return m_storage.storage.m_has_value ? detail::forward<U>(default_error) 4246 : static_cast<E&&>(m_storage.storage.m_error); 4247 } 4248 4249 template<typename T, typename E> 4250 template<typename U> 4251 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::and_then(U&& value) const 4252 -> result<typename std::decay<U>::type, E> 4253 { 4254 return map([&value](const T&) { 4255 return detail::forward<U>(value); 4256 }); 4257 } 4258 4259 //----------------------------------------------------------------------------- 4260 4261 template<typename T, typename E> 4262 template<typename Fn> 4263 inline RESULT_INLINE_VISIBILITY constexpr auto 4264 RESULT_NS_IMPL::result<T, E>::flat_map(Fn&& fn) const& -> detail::invoke_result_t<Fn, const T&> 4265 { 4266 using result_type = detail::invoke_result_t<Fn, const T&>; 4267 4268 static_assert(is_result<result_type>::value, "flat_map must return a result type or the program is ill-formed"); 4269 4270 return has_value() ? detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_value) 4271 : result_type(in_place_error, m_storage.storage.m_error); 4272 } 4273 4274 template<typename T, typename E> 4275 template<typename Fn> 4276 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4277 RESULT_NS_IMPL::result<T, E>::flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn, T&&> 4278 { 4279 using result_type = detail::invoke_result_t<Fn, T&&>; 4280 4281 static_assert(is_result<result_type>::value, "flat_map must return a result type or the program is ill-formed"); 4282 4283 return has_value() ? detail::invoke(detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value)) 4284 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4285 } 4286 4287 template<typename T, typename E> 4288 template<typename Fn> 4289 inline RESULT_INLINE_VISIBILITY constexpr auto 4290 RESULT_NS_IMPL::result<T, E>::map(Fn&& fn) const& -> result<detail::invoke_result_t<Fn, const T&>, E> 4291 { 4292 using result_type = detail::invoke_result_t<Fn, const T&>; 4293 4294 return map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn)); 4295 } 4296 4297 template<typename T, typename E> 4298 template<typename Fn> 4299 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4300 RESULT_NS_IMPL::result<T, E>::map(Fn&& fn) && -> result<detail::invoke_result_t<Fn, T&&>, E> 4301 { 4302 using result_type = detail::invoke_result_t<Fn, T&&>; 4303 4304 return static_cast<result<T, E>&&>(*this).map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn)); 4305 } 4306 4307 //----------------------------------------------------------------------------- 4308 4309 template<typename T, typename E> 4310 template<typename Fn> 4311 inline RESULT_INLINE_VISIBILITY constexpr auto 4312 RESULT_NS_IMPL::result<T, E>::map_error(Fn&& fn) const& -> result<T, detail::invoke_result_t<Fn, const E&>> 4313 { 4314 using result_type = result<T, detail::invoke_result_t<Fn, const E&>>; 4315 4316 return has_error() ? result_type(in_place_error, detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error)) 4317 : result_type(in_place, m_storage.storage.m_value); 4318 } 4319 4320 template<typename T, typename E> 4321 template<typename Fn> 4322 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4323 RESULT_NS_IMPL::result<T, E>::map_error(Fn&& fn) && -> result<T, detail::invoke_result_t<Fn, E&&>> 4324 { 4325 using result_type = result<T, detail::invoke_result_t<Fn, E&&>>; 4326 4327 return has_error() 4328 ? result_type(in_place_error, 4329 detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error))) 4330 : result_type(static_cast<T&&>(m_storage.storage.m_value)); 4331 } 4332 4333 template<typename T, typename E> 4334 template<typename Fn> 4335 inline RESULT_INLINE_VISIBILITY constexpr auto 4336 RESULT_NS_IMPL::result<T, E>::flat_map_error(Fn&& fn) const& -> detail::invoke_result_t<Fn, const E&> 4337 { 4338 using result_type = detail::invoke_result_t<Fn, const E&>; 4339 4340 static_assert(is_result<result_type>::value, 4341 "flat_map_error must return a result type or the program is ill-formed"); 4342 4343 return has_value() ? result_type(in_place, m_storage.storage.m_value) 4344 : detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error); 4345 } 4346 4347 template<typename T, typename E> 4348 template<typename Fn> 4349 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4350 RESULT_NS_IMPL::result<T, E>::flat_map_error(Fn&& fn) && -> detail::invoke_result_t<Fn, E&&> 4351 { 4352 using result_type = detail::invoke_result_t<Fn, E&&>; 4353 4354 static_assert(is_result<result_type>::value, 4355 "flat_map_error must return a result type or the program is ill-formed"); 4356 4357 return has_value() ? result_type(in_place, static_cast<T&&>(m_storage.storage.m_value)) 4358 : detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error)); 4359 } 4360 4361 //----------------------------------------------------------------------------- 4362 // Private Monadic Functions 4363 //----------------------------------------------------------------------------- 4364 4365 template<typename T, typename E> 4366 template<typename Fn> 4367 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<T, E>::map_impl(std::true_type, 4368 Fn&& fn) const& -> result<void, E> 4369 { 4370 using result_type = result<void, E>; 4371 4372 return has_value() ? (detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_value), result_type{}) 4373 : result_type(in_place_error, m_storage.storage.m_error); 4374 } 4375 4376 template<typename T, typename E> 4377 template<typename Fn> 4378 inline RESULT_INLINE_VISIBILITY constexpr auto 4379 RESULT_NS_IMPL::result<T, E>::map_impl(std::false_type, 4380 Fn&& fn) const& -> result<detail::invoke_result_t<Fn, const T&>, E> 4381 { 4382 using invoke_result_type = detail::invoke_result_t<Fn, const T&>; 4383 using result_type = result<invoke_result_type, E>; 4384 4385 return has_value() ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_value)) 4386 : result_type(in_place_error, m_storage.storage.m_error); 4387 } 4388 4389 template<typename T, typename E> 4390 template<typename Fn> 4391 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4392 RESULT_NS_IMPL::result<T, E>::map_impl(std::true_type, Fn&& fn) && -> result<void, E> 4393 { 4394 using result_type = result<void, E>; 4395 4396 return has_value() 4397 ? (detail::invoke(detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value)), result_type{}) 4398 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4399 } 4400 4401 template<typename T, typename E> 4402 template<typename Fn> 4403 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4404 RESULT_NS_IMPL::result<T, E>::map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn, T&&>, E> 4405 { 4406 using invoke_result_type = detail::invoke_result_t<Fn, T&&>; 4407 using result_type = result<invoke_result_type, E>; 4408 4409 return has_value() 4410 ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn), static_cast<T&&>(m_storage.storage.m_value))) 4411 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4412 } 4413 4414 //============================================================================= 4415 // class : result<void,E> 4416 //============================================================================= 4417 4418 //----------------------------------------------------------------------------- 4419 // Constructor / Assignment 4420 //----------------------------------------------------------------------------- 4421 4422 template<typename E> 4423 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result() noexcept: m_storage(in_place) 4424 { 4425 } 4426 4427 template<typename E> 4428 template<typename U, typename E2, typename> 4429 inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::result<void, E>::result(const result<U, E2>& other) noexcept( 4430 std::is_nothrow_constructible<E, const E2&>::value): 4431 m_storage(detail::unit{}) 4432 { 4433 m_storage.construct_error_from_result(static_cast<const result<U, E2>&>(other).m_storage); 4434 } 4435 4436 template<typename E> 4437 template<typename U, typename E2, typename> 4438 inline RESULT_INLINE_VISIBILITY 4439 RESULT_NS_IMPL::result<void, E>::result(result<U, E2>&& other) noexcept(std::is_nothrow_constructible<E, E2&&>::value): 4440 m_storage(detail::unit{}) 4441 { 4442 m_storage.construct_error_from_result(static_cast<result<U, E2>&&>(other).m_storage); 4443 } 4444 4445 //----------------------------------------------------------------------------- 4446 4447 template<typename E> 4448 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result(in_place_t) noexcept: 4449 m_storage(in_place) 4450 { 4451 } 4452 4453 template<typename E> 4454 template<typename... Args, typename> 4455 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result( 4456 in_place_error_t, Args&&...args) noexcept(std::is_nothrow_constructible<E, Args...>::value): 4457 m_storage(in_place_error, detail::forward<Args>(args)...) 4458 { 4459 } 4460 4461 template<typename E> 4462 template<typename U, typename... Args, typename> 4463 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result( 4464 in_place_error_t, 4465 std::initializer_list<U> ilist, 4466 Args&&...args) noexcept(std::is_nothrow_constructible<E, std::initializer_list<U>, Args...>::value): 4467 m_storage(in_place_error, ilist, detail::forward<Args>(args)...) 4468 { 4469 } 4470 4471 //----------------------------------------------------------------------------- 4472 4473 template<typename E> 4474 template<typename E2, typename> 4475 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result(const failure<E2>& e) noexcept( 4476 std::is_nothrow_constructible<E, const E2&>::value): 4477 m_storage(in_place_error, e.error()) 4478 { 4479 } 4480 4481 template<typename E> 4482 template<typename E2, typename> 4483 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::result(failure<E2>&& e) noexcept( 4484 std::is_nothrow_constructible<E, E2&&>::value): 4485 m_storage(in_place_error, static_cast<E2&&>(e.error())) 4486 { 4487 } 4488 4489 //----------------------------------------------------------------------------- 4490 4491 template<typename E> 4492 template<typename E2, typename> 4493 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<void, E>::operator=(const result<void, E2>& other) noexcept( 4494 std::is_nothrow_assignable<E, const E2&>::value) -> result& 4495 { 4496 m_storage.assign_from_result(other.m_storage); 4497 return (*this); 4498 } 4499 4500 template<typename E> 4501 template<typename E2, typename> 4502 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<void, E>::operator=(result<void, E2>&& other) noexcept( 4503 std::is_nothrow_assignable<E, E2&&>::value) -> result& 4504 { 4505 m_storage.assign_from_result(static_cast<result<void, E2>&&>(other).m_storage); 4506 return (*this); 4507 } 4508 4509 template<typename E> 4510 template<typename E2, typename> 4511 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::result<void, E>::operator=(const failure<E2>& other) noexcept( 4512 std::is_nothrow_assignable<E, const E2&>::value) -> result& 4513 { 4514 m_storage.assign_error(other.error()); 4515 return (*this); 4516 } 4517 4518 template<typename E> 4519 template<typename E2, typename> 4520 inline RESULT_INLINE_VISIBILITY auto 4521 RESULT_NS_IMPL::result<void, E>::operator=(failure<E2>&& other) noexcept(std::is_nothrow_assignable<E, E2&&>::value) 4522 -> result& 4523 { 4524 m_storage.assign_error(static_cast<E2&&>(other.error())); 4525 return (*this); 4526 } 4527 4528 //----------------------------------------------------------------------------- 4529 // Observers 4530 //----------------------------------------------------------------------------- 4531 4532 template<typename E> 4533 inline RESULT_INLINE_VISIBILITY constexpr RESULT_NS_IMPL::result<void, E>::operator bool() const noexcept 4534 { 4535 return has_value(); 4536 } 4537 4538 template<typename E> 4539 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<void, E>::has_value() const noexcept -> bool 4540 { 4541 return m_storage.storage.m_has_value; 4542 } 4543 4544 template<typename E> 4545 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<void, E>::has_error() const noexcept -> bool 4546 { 4547 return !has_value(); 4548 } 4549 4550 //----------------------------------------------------------------------------- 4551 4552 template<typename E> 4553 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<void, E>::value() const& -> void 4554 { 4555 static_cast<void>(has_value() || (detail::throw_bad_result_access(m_storage.storage.m_error), true)); 4556 } 4557 4558 template<typename E> 4559 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<void, E>::value() && -> void 4560 { 4561 static_cast<void>(has_value() 4562 || (detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true)); 4563 } 4564 4565 template<typename E> 4566 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<void, E>::error() const& noexcept( 4567 std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) -> E 4568 { 4569 return has_value() ? E{} : m_storage.storage.m_error; 4570 } 4571 4572 template<typename E> 4573 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<void, E>::error() && noexcept( 4574 std::is_nothrow_constructible<E>::value&& std::is_nothrow_copy_constructible<E>::value) -> E 4575 { 4576 return has_value() ? E{} : static_cast<E&&>(m_storage.storage.m_error); 4577 } 4578 4579 //----------------------------------------------------------------------------- 4580 4581 template<typename E> 4582 template<typename String, typename> 4583 inline RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<void, E>::expect(String&& message) const& -> void 4584 { 4585 if (has_error()) { 4586 detail::throw_bad_result_access_message(detail::forward<String>(message), m_storage.storage.m_error); 4587 } 4588 } 4589 4590 template<typename E> 4591 template<typename String, typename> 4592 inline RESULT_CPP14_CONSTEXPR auto RESULT_NS_IMPL::result<void, E>::expect(String&& message) && -> void 4593 { 4594 if (has_error()) { 4595 detail::throw_bad_result_access_message(detail::forward<String>(message), 4596 static_cast<E&&>(m_storage.storage.m_error)); 4597 } 4598 } 4599 4600 //----------------------------------------------------------------------------- 4601 // Monadic Functionalities 4602 //----------------------------------------------------------------------------- 4603 4604 template<typename E> 4605 template<typename U> 4606 inline RESULT_INLINE_VISIBILITY constexpr auto 4607 RESULT_NS_IMPL::result<void, E>::error_or(U&& default_error) const& -> error_type 4608 { 4609 return has_value() ? detail::forward<U>(default_error) : m_storage.storage.m_error; 4610 } 4611 4612 template<typename E> 4613 template<typename U> 4614 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4615 RESULT_NS_IMPL::result<void, E>::error_or(U&& default_error) && -> error_type 4616 { 4617 return has_value() ? detail::forward<U>(default_error) : static_cast<E&&>(m_storage.storage.m_error); 4618 } 4619 4620 template<typename E> 4621 template<typename U> 4622 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::result<void, E>::and_then(U&& value) const 4623 -> result<typename std::decay<U>::type, E> 4624 { 4625 return map([&value] { 4626 return detail::forward<U>(value); 4627 }); 4628 } 4629 4630 //----------------------------------------------------------------------------- 4631 4632 template<typename E> 4633 template<typename Fn> 4634 inline RESULT_INLINE_VISIBILITY constexpr auto 4635 RESULT_NS_IMPL::result<void, E>::flat_map(Fn&& fn) const& -> detail::invoke_result_t<Fn> 4636 { 4637 using result_type = detail::invoke_result_t<Fn>; 4638 4639 static_assert(is_result<result_type>::value, "flat_map must return a result type or the program is ill-formed"); 4640 4641 return has_value() ? detail::invoke(detail::forward<Fn>(fn)) 4642 : result_type(in_place_error, m_storage.storage.m_error); 4643 } 4644 4645 template<typename E> 4646 template<typename Fn> 4647 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4648 RESULT_NS_IMPL::result<void, E>::flat_map(Fn&& fn) && -> detail::invoke_result_t<Fn> 4649 { 4650 using result_type = detail::invoke_result_t<Fn>; 4651 4652 static_assert(is_result<result_type>::value, "flat_map must return a result type or the program is ill-formed"); 4653 4654 return has_value() ? detail::invoke(detail::forward<Fn>(fn)) 4655 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4656 } 4657 4658 template<typename E> 4659 template<typename Fn> 4660 inline RESULT_INLINE_VISIBILITY constexpr auto 4661 RESULT_NS_IMPL::result<void, E>::map(Fn&& fn) const& -> result<detail::invoke_result_t<Fn>, E> 4662 { 4663 using result_type = detail::invoke_result_t<Fn>; 4664 4665 return map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn)); 4666 } 4667 4668 template<typename E> 4669 template<typename Fn> 4670 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4671 RESULT_NS_IMPL::result<void, E>::map(Fn&& fn) && -> result<detail::invoke_result_t<Fn>, E> 4672 { 4673 using result_type = detail::invoke_result_t<Fn>; 4674 4675 return static_cast<result<void, E>&&>(*this).map_impl(std::is_void<result_type>{}, detail::forward<Fn>(fn)); 4676 } 4677 4678 //----------------------------------------------------------------------------- 4679 4680 template<typename E> 4681 template<typename Fn> 4682 inline RESULT_INLINE_VISIBILITY constexpr auto 4683 RESULT_NS_IMPL::result<void, E>::map_error(Fn&& fn) const& -> result<void, detail::invoke_result_t<Fn, const E&>> 4684 { 4685 using result_type = result<void, detail::invoke_result_t<Fn, const E&>>; 4686 4687 return has_value() 4688 ? result_type{} 4689 : result_type(in_place_error, detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error)); 4690 } 4691 4692 template<typename E> 4693 template<typename Fn> 4694 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4695 RESULT_NS_IMPL::result<void, E>::map_error(Fn&& fn) && -> result<void, detail::invoke_result_t<Fn, E&&>> 4696 { 4697 using result_type = result<void, detail::invoke_result_t<Fn, E&&>>; 4698 4699 return has_value() 4700 ? result_type{} 4701 : result_type(in_place_error, 4702 detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error))); 4703 } 4704 4705 template<typename E> 4706 template<typename Fn> 4707 inline RESULT_INLINE_VISIBILITY constexpr auto 4708 RESULT_NS_IMPL::result<void, E>::flat_map_error(Fn&& fn) const& -> detail::invoke_result_t<Fn, const E&> 4709 { 4710 using result_type = detail::invoke_result_t<Fn, const E&>; 4711 4712 static_assert(is_result<result_type>::value, 4713 "flat_map_error must return a result type or the program is ill-formed"); 4714 static_assert(std::is_default_constructible<typename result_type::value_type>::value, 4715 "flat_map_error for result<void,E> requires the new T type to be default-" 4716 "constructible"); 4717 4718 return has_value() ? result_type{} : detail::invoke(detail::forward<Fn>(fn), m_storage.storage.m_error); 4719 } 4720 4721 template<typename E> 4722 template<typename Fn> 4723 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4724 RESULT_NS_IMPL::result<void, E>::flat_map_error(Fn&& fn) && -> detail::invoke_result_t<Fn, E&&> 4725 { 4726 using result_type = detail::invoke_result_t<Fn, E&&>; 4727 4728 static_assert(is_result<result_type>::value, 4729 "flat_map_error must return a result type or the program is ill-formed"); 4730 static_assert(std::is_default_constructible<typename result_type::value_type>::value, 4731 "flat_map_error for result<void,E> requires the new T type to be default-" 4732 "constructible"); 4733 4734 return has_value() ? result_type{} 4735 : detail::invoke(detail::forward<Fn>(fn), static_cast<E&&>(m_storage.storage.m_error)); 4736 } 4737 4738 //----------------------------------------------------------------------------- 4739 // Private Monadic Functions 4740 //----------------------------------------------------------------------------- 4741 4742 template<typename E> 4743 template<typename Fn> 4744 inline RESULT_INLINE_VISIBILITY constexpr auto 4745 RESULT_NS_IMPL::result<void, E>::map_impl(std::true_type, Fn&& fn) const& -> result<void, E> 4746 { 4747 using result_type = result<void, E>; 4748 4749 return has_value() ? (detail::invoke(detail::forward<Fn>(fn)), result_type{}) 4750 : result_type(in_place_error, m_storage.storage.m_error); 4751 } 4752 4753 template<typename E> 4754 template<typename Fn> 4755 inline RESULT_INLINE_VISIBILITY constexpr auto 4756 RESULT_NS_IMPL::result<void, E>::map_impl(std::false_type, Fn&& fn) const& -> result<detail::invoke_result_t<Fn>, E> 4757 { 4758 using invoke_result_type = detail::invoke_result_t<Fn>; 4759 using result_type = result<invoke_result_type, E>; 4760 4761 return has_value() ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn))) 4762 : result_type(in_place_error, m_storage.storage.m_error); 4763 } 4764 4765 template<typename E> 4766 template<typename Fn> 4767 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4768 RESULT_NS_IMPL::result<void, E>::map_impl(std::true_type, Fn&& fn) && -> result<void, E> 4769 { 4770 using result_type = result<void, E>; 4771 4772 return has_value() ? (detail::invoke(detail::forward<Fn>(fn)), result_type{}) 4773 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4774 } 4775 4776 template<typename E> 4777 template<typename Fn> 4778 inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR auto 4779 RESULT_NS_IMPL::result<void, E>::map_impl(std::false_type, Fn&& fn) && -> result<detail::invoke_result_t<Fn>, E> 4780 { 4781 using invoke_result_type = detail::invoke_result_t<Fn>; 4782 using result_type = result<invoke_result_type, E>; 4783 4784 return has_value() ? result_type(in_place, detail::invoke(detail::forward<Fn>(fn))) 4785 : result_type(in_place_error, static_cast<E&&>(m_storage.storage.m_error)); 4786 } 4787 4788 //============================================================================= 4789 // non-member functions : class : result 4790 //============================================================================= 4791 4792 //----------------------------------------------------------------------------- 4793 // Comparison 4794 //----------------------------------------------------------------------------- 4795 4796 template<typename T1, typename E1, typename T2, typename E2> 4797 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const result<T1, E1>& lhs, 4798 const result<T2, E2>& rhs) noexcept -> bool 4799 { 4800 return (lhs.has_value() == rhs.has_value()) 4801 ? (lhs.has_value() ? *lhs == *rhs : detail::extract_error(lhs) == detail::extract_error(rhs)) 4802 : false; 4803 } 4804 4805 template<typename T1, typename E1, typename T2, typename E2> 4806 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const result<T1, E1>& lhs, 4807 const result<T2, E2>& rhs) noexcept -> bool 4808 { 4809 return (lhs.has_value() == rhs.has_value()) 4810 ? (lhs.has_value() ? *lhs != *rhs : detail::extract_error(lhs) != detail::extract_error(rhs)) 4811 : true; 4812 } 4813 4814 template<typename T1, typename E1, typename T2, typename E2> 4815 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const result<T1, E1>& lhs, 4816 const result<T2, E2>& rhs) noexcept -> bool 4817 { 4818 return (lhs.has_value() == rhs.has_value()) 4819 ? (lhs.has_value() ? *lhs >= *rhs : detail::extract_error(lhs) >= detail::extract_error(rhs)) 4820 : static_cast<int>(static_cast<bool>(lhs)) >= static_cast<int>(static_cast<bool>(rhs)); 4821 } 4822 4823 template<typename T1, typename E1, typename T2, typename E2> 4824 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const result<T1, E1>& lhs, 4825 const result<T2, E2>& rhs) noexcept -> bool 4826 { 4827 return (lhs.has_value() == rhs.has_value()) 4828 ? (lhs.has_value() ? *lhs <= *rhs : detail::extract_error(lhs) <= detail::extract_error(rhs)) 4829 : static_cast<int>(static_cast<bool>(lhs)) <= static_cast<int>(static_cast<bool>(rhs)); 4830 } 4831 4832 template<typename T1, typename E1, typename T2, typename E2> 4833 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const result<T1, E1>& lhs, 4834 const result<T2, E2>& rhs) noexcept -> bool 4835 { 4836 return (lhs.has_value() == rhs.has_value()) 4837 ? (lhs.has_value() ? *lhs > *rhs : detail::extract_error(lhs) > detail::extract_error(rhs)) 4838 : static_cast<int>(static_cast<bool>(lhs)) > static_cast<int>(static_cast<bool>(rhs)); 4839 } 4840 4841 template<typename T1, typename E1, typename T2, typename E2> 4842 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const result<T1, E1>& lhs, 4843 const result<T2, E2>& rhs) noexcept -> bool 4844 { 4845 return (lhs.has_value() == rhs.has_value()) 4846 ? (lhs.has_value() ? *lhs < *rhs : detail::extract_error(lhs) < detail::extract_error(rhs)) 4847 : static_cast<int>(static_cast<bool>(lhs)) < static_cast<int>(static_cast<bool>(rhs)); 4848 } 4849 4850 //----------------------------------------------------------------------------- 4851 4852 template<typename E1, typename E2> 4853 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const result<void, E1>& lhs, 4854 const result<void, E2>& rhs) noexcept -> bool 4855 { 4856 return lhs.has_value() == rhs.has_value() 4857 ? (lhs.has_value() ? true : detail::extract_error(lhs) == detail::extract_error(rhs)) 4858 : false; 4859 } 4860 4861 template<typename E1, typename E2> 4862 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const result<void, E1>& lhs, 4863 const result<void, E2>& rhs) noexcept -> bool 4864 { 4865 return lhs.has_value() == rhs.has_value() 4866 ? (lhs.has_value() ? false : detail::extract_error(lhs) != detail::extract_error(rhs)) 4867 : true; 4868 } 4869 4870 template<typename E1, typename E2> 4871 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const result<void, E1>& lhs, 4872 const result<void, E2>& rhs) noexcept -> bool 4873 { 4874 return lhs.has_value() == rhs.has_value() 4875 ? (lhs.has_value() ? true : detail::extract_error(lhs) >= detail::extract_error(rhs)) 4876 : static_cast<int>(static_cast<bool>(lhs)) >= static_cast<int>(static_cast<bool>(rhs)); 4877 } 4878 4879 template<typename E1, typename E2> 4880 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const result<void, E1>& lhs, 4881 const result<void, E2>& rhs) noexcept -> bool 4882 { 4883 return lhs.has_value() == rhs.has_value() 4884 ? (lhs.has_value() ? true : detail::extract_error(lhs) <= detail::extract_error(rhs)) 4885 : static_cast<int>(static_cast<bool>(lhs)) <= static_cast<int>(static_cast<bool>(rhs)); 4886 } 4887 4888 template<typename E1, typename E2> 4889 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const result<void, E1>& lhs, 4890 const result<void, E2>& rhs) noexcept -> bool 4891 { 4892 return lhs.has_value() == rhs.has_value() 4893 ? (lhs.has_value() ? false : detail::extract_error(lhs) > detail::extract_error(rhs)) 4894 : static_cast<int>(static_cast<bool>(lhs)) > static_cast<int>(static_cast<bool>(rhs)); 4895 } 4896 4897 template<typename E1, typename E2> 4898 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const result<void, E1>& lhs, 4899 const result<void, E2>& rhs) noexcept -> bool 4900 { 4901 return lhs.has_value() == rhs.has_value() 4902 ? (lhs.has_value() ? false : detail::extract_error(lhs) < detail::extract_error(rhs)) 4903 : static_cast<int>(static_cast<bool>(lhs)) < static_cast<int>(static_cast<bool>(rhs)); 4904 } 4905 4906 //----------------------------------------------------------------------------- 4907 4908 template<typename T, typename E, typename U, typename> 4909 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const result<T, E>& exp, 4910 const U& value) noexcept -> bool 4911 { 4912 return (exp.has_value() && *exp == value); 4913 } 4914 4915 template<typename T, typename U, typename E, typename> 4916 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const T& value, 4917 const result<U, E>& exp) noexcept -> bool 4918 { 4919 return (exp.has_value() && *exp == value); 4920 } 4921 4922 template<typename T, typename E, typename U, typename> 4923 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const result<T, E>& exp, 4924 const U& value) noexcept -> bool 4925 { 4926 return exp.has_value() ? *exp != value : true; 4927 } 4928 4929 template<typename T, typename U, typename E, typename> 4930 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const T& value, 4931 const result<U, E>& exp) noexcept -> bool 4932 { 4933 return exp.has_value() ? value != *exp : true; 4934 } 4935 4936 template<typename T, typename E, typename U, typename> 4937 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const result<T, E>& exp, 4938 const U& value) noexcept -> bool 4939 { 4940 return exp.has_value() ? *exp <= value : false; 4941 } 4942 4943 template<typename T, typename U, typename E, typename> 4944 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const T& value, 4945 const result<U, E>& exp) noexcept -> bool 4946 { 4947 return exp.has_value() ? value <= *exp : true; 4948 } 4949 4950 template<typename T, typename E, typename U, typename> 4951 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const result<T, E>& exp, 4952 const U& value) noexcept -> bool 4953 { 4954 return exp.has_value() ? *exp >= value : true; 4955 } 4956 4957 template<typename T, typename U, typename E, typename> 4958 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const T& value, 4959 const result<U, E>& exp) noexcept -> bool 4960 { 4961 return exp.has_value() ? value >= *exp : false; 4962 } 4963 4964 template<typename T, typename E, typename U, typename> 4965 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const result<T, E>& exp, 4966 const U& value) noexcept -> bool 4967 { 4968 return exp.has_value() ? *exp < value : false; 4969 } 4970 4971 template<typename T, typename U, typename E, typename> 4972 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const T& value, 4973 const result<U, E>& exp) noexcept -> bool 4974 { 4975 return exp.has_value() ? value < *exp : true; 4976 } 4977 4978 template<typename T, typename E, typename U, typename> 4979 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const result<T, E>& exp, 4980 const U& value) noexcept -> bool 4981 { 4982 return exp.has_value() ? *exp > value : false; 4983 } 4984 4985 template<typename T, typename U, typename E, typename> 4986 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const T& value, 4987 const result<U, E>& exp) noexcept -> bool 4988 { 4989 return exp.has_value() ? value > *exp : true; 4990 } 4991 4992 //----------------------------------------------------------------------------- 4993 4994 template<typename T, typename E, typename U> 4995 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const result<T, E>& exp, 4996 const failure<U>& error) noexcept -> bool 4997 { 4998 return exp.has_error() ? detail::extract_error(exp) == error.error() : false; 4999 } 5000 5001 template<typename T, typename U, typename E> 5002 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator==(const failure<T>& error, 5003 const result<E, U>& exp) noexcept -> bool 5004 { 5005 return exp.has_error() ? error.error() == detail::extract_error(exp) : false; 5006 } 5007 5008 template<typename T, typename E, typename U> 5009 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const result<T, E>& exp, 5010 const failure<U>& error) noexcept -> bool 5011 { 5012 return exp.has_error() ? detail::extract_error(exp) != error.error() : true; 5013 } 5014 5015 template<typename T, typename U, typename E> 5016 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator!=(const failure<T>& error, 5017 const result<E, U>& exp) noexcept -> bool 5018 { 5019 return exp.has_error() ? error.error() != detail::extract_error(exp) : true; 5020 } 5021 5022 template<typename T, typename E, typename U> 5023 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const result<T, E>& exp, 5024 const failure<U>& error) noexcept -> bool 5025 { 5026 return exp.has_error() ? detail::extract_error(exp) <= error.error() : true; 5027 } 5028 5029 template<typename T, typename U, typename E> 5030 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<=(const failure<T>& error, 5031 const result<E, U>& exp) noexcept -> bool 5032 { 5033 return exp.has_error() ? error.error() <= detail::extract_error(exp) : false; 5034 } 5035 5036 template<typename T, typename E, typename U> 5037 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const result<T, E>& exp, 5038 const failure<U>& error) noexcept -> bool 5039 { 5040 return exp.has_error() ? detail::extract_error(exp) >= error.error() : false; 5041 } 5042 5043 template<typename T, typename U, typename E> 5044 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>=(const failure<T>& error, 5045 const result<E, U>& exp) noexcept -> bool 5046 { 5047 return exp.has_error() ? error.error() >= detail::extract_error(exp) : true; 5048 } 5049 5050 template<typename T, typename E, typename U> 5051 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const result<T, E>& exp, 5052 const failure<U>& error) noexcept -> bool 5053 { 5054 return exp.has_error() ? detail::extract_error(exp) < error.error() : true; 5055 } 5056 5057 template<typename T, typename U, typename E> 5058 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator<(const failure<T>& error, 5059 const result<E, U>& exp) noexcept -> bool 5060 { 5061 return exp.has_error() ? error.error() < detail::extract_error(exp) : false; 5062 } 5063 5064 template<typename T, typename E, typename U> 5065 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const result<T, E>& exp, 5066 const failure<U>& error) noexcept -> bool 5067 { 5068 return exp.has_error() ? detail::extract_error(exp) > error.error() : false; 5069 } 5070 5071 template<typename T, typename U, typename E> 5072 inline RESULT_INLINE_VISIBILITY constexpr auto RESULT_NS_IMPL::operator>(const failure<T>& error, 5073 const result<E, U>& exp) noexcept -> bool 5074 { 5075 return exp.has_error() ? error.error() > detail::extract_error(exp) : true; 5076 } 5077 5078 //----------------------------------------------------------------------------- 5079 // Utilities 5080 //----------------------------------------------------------------------------- 5081 5082 template<typename T, typename E> 5083 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::swap(result<T, E>& lhs, result<T, E>& rhs) 5084 #if __cplusplus >= 201703L 5085 noexcept( 5086 std::is_nothrow_move_constructible<result<T, E>>::value&& std::is_nothrow_move_assignable<result<T, E>>::value&& 5087 std::is_nothrow_swappable<T>::value&& std::is_nothrow_swappable<E>::value) 5088 #else 5089 noexcept( 5090 std::is_nothrow_move_constructible<result<T, E>>::value&& std::is_nothrow_move_assignable<result<T, E>>::value) 5091 #endif 5092 -> void 5093 { 5094 using std::swap; 5095 5096 if (lhs.has_value() == rhs.has_value()) { 5097 if (lhs.has_value()) { 5098 swap(*lhs, *rhs); 5099 } else { 5100 auto& lhs_error = detail::result_error_extractor::get(lhs); 5101 auto& rhs_error = detail::result_error_extractor::get(rhs); 5102 5103 swap(lhs_error, rhs_error); 5104 } 5105 // If both `result`s contain values, do nothing 5106 } else { 5107 auto temp = static_cast<result<T, E>&&>(lhs); 5108 lhs = static_cast<result<T, E>&&>(rhs); 5109 rhs = static_cast<result<T, E>&&>(temp); 5110 } 5111 } 5112 5113 template<typename E> 5114 inline RESULT_INLINE_VISIBILITY auto RESULT_NS_IMPL::swap(result<void, E>& lhs, result<void, E>& rhs) 5115 #if __cplusplus >= 201703L 5116 noexcept(std::is_nothrow_move_constructible<result<void, E>>::value&& 5117 std::is_nothrow_move_assignable<result<void, E>>::value&& std::is_nothrow_swappable<E>::value) 5118 #else 5119 noexcept(std::is_nothrow_move_constructible<result<void, E>>::value&& 5120 std::is_nothrow_move_assignable<result<void, E>>::value) 5121 #endif 5122 -> void 5123 { 5124 using std::swap; 5125 5126 if (lhs.has_value() == rhs.has_value()) { 5127 if (lhs.has_error()) { 5128 auto& lhs_error = detail::result_error_extractor::get(lhs); 5129 auto& rhs_error = detail::result_error_extractor::get(rhs); 5130 5131 swap(lhs_error, rhs_error); 5132 } 5133 // If both `result`s contain values, do nothing 5134 } else { 5135 auto temp = static_cast<result<void, E>&&>(lhs); 5136 lhs = static_cast<result<void, E>&&>(rhs); 5137 rhs = static_cast<result<void, E>&&>(temp); 5138 } 5139 } 5140 5141 #if defined(__clang__) 5142 #pragma clang diagnostic pop 5143 #endif 5144 5145 #undef RESULT_NAMESPACE_INTERNAL 5146 #undef RESULT_NS_IMPL 5147 #undef RESULT_CPP14_CONSTEXPR 5148 #undef RESULT_CPP17_INLINE 5149 #undef RESULT_INLINE_VISIBILITY 5150 #undef RESULT_NODISCARD 5151 #undef RESULT_WARN_UNUSED 5152 5153 #endif /* RESULT_RESULT_HPP */