diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp index e0105a9..c5d5984 100644 --- a/include/tl/expected.hpp +++ b/include/tl/expected.hpp @@ -1,6 +1,8 @@ /// // expected - An implementation of std::expected with extensions -// Written in 2017 by Simon Brand (@TartanLlama) +// Written in 2017 by Simon Brand (@TartanLlama, simonrbrand@gmail.com) +// +// Documentation available at http://tl.tartanllama.xyz/ // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to the @@ -28,7 +30,6 @@ #endif #if (defined(_MSC_VER) && _MSC_VER == 1900) -/// \exclude #define TL_EXPECTED_MSVC2015 #define TL_EXPECTED_MSVC2015_CONSTEXPR #else @@ -37,38 +38,31 @@ #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) -/// \exclude #define TL_EXPECTED_GCC49 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ !defined(__clang__)) -/// \exclude #define TL_EXPECTED_GCC54 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ !defined(__clang__)) -/// \exclude #define TL_EXPECTED_GCC55 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) // GCC < 5 doesn't support overloading on const&& for member functions -/// \exclude -#define TL_EXPECTED_NO_CONSTRR +#define TL_EXPECTED_NO_CONSTRR // GCC < 5 doesn't support some standard C++11 type traits -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::has_trivial_copy_constructor -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::has_trivial_copy_assign // This one will be different for GCC 5.7 if it's ever supported -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible @@ -97,19 +91,15 @@ namespace tl { std::is_trivially_copy_assignable #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible #else -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::is_trivially_copy_constructible -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable -/// \exclude #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible #endif #if __cplusplus > 201103L -/// \exclude #define TL_EXPECTED_CXX14 #endif @@ -121,10 +111,8 @@ namespace tl { #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \ defined(TL_EXPECTED_GCC49)) -/// \exclude #define TL_EXPECTED_11_CONSTEXPR #else -/// \exclude #define TL_EXPECTED_11_CONSTEXPR constexpr #endif @@ -133,18 +121,14 @@ template class expected; #ifndef TL_MONOSTATE_INPLACE_MUTEX #define TL_MONOSTATE_INPLACE_MUTEX -/// \brief Used to represent an expected with no data class monostate {}; -/// \brief A tag type to tell expected to construct its value in-place struct in_place_t { explicit in_place_t() = default; }; -/// \brief A tag to tell expected to construct its value in-place static constexpr in_place_t in_place{}; #endif -/// Used as a wrapper to store the unexpected value template class unexpected { public: static_assert(!std::is_same::value, "E must not be void"); @@ -154,7 +138,6 @@ public: constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} - /// Returns the contained value constexpr const E &value() const & { return m_val; } TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } @@ -164,7 +147,6 @@ private: E m_val; }; -/// Compares two unexpected objects template constexpr bool operator==(const unexpected &lhs, const unexpected &rhs) { return lhs.value() == rhs.value(); @@ -190,20 +172,16 @@ constexpr bool operator>=(const unexpected &lhs, const unexpected &rhs) { return lhs.value() >= rhs.value(); } -/// Create an `unexpected` from `e`, deducing the return type template unexpected::type> make_unexpected(E &&e) { return unexpected::type>(std::forward(e)); } -/// A tag type to tell expected to construct the unexpected value struct unexpect_t { unexpect_t() = default; }; -/// A tag to tell expected to construct the unexpected value static constexpr unexpect_t unexpect{}; -/// \exclude namespace detail { template [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { @@ -426,7 +404,6 @@ using is_move_assignable_or_void = } // namespace detail -/// \exclude namespace detail { struct no_init_t {}; static constexpr no_init_t no_init{}; @@ -1276,65 +1253,33 @@ public: #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// \group and_then - /// Carries out some operation which returns an expected on the stored object - /// if there is one. \requires `std::invoke(std::forward(f), value())` - /// returns an `expected` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward(f), value())`. Returns an - /// `expected`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. - /// \synopsis template \nconstexpr auto and_then(F &&f) &; template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { return and_then_impl(*this, std::forward(f)); } - - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &&; template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { return and_then_impl(std::move(*this), std::forward(f)); } - - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &; template constexpr auto and_then(F &&f) const & { return and_then_impl(*this, std::forward(f)); } #ifndef TL_EXPECTED_NO_CONSTRR - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; template constexpr auto and_then(F &&f) const && { return and_then_impl(std::move(*this), std::forward(f)); } #endif #else - /// \group and_then - /// Carries out some operation which returns an expected on the stored object - /// if there is one. \requires `std::invoke(std::forward(f), value())` - /// returns an `expected` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward(f), value())`. Returns an - /// `expected`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. - /// \synopsis template \nconstexpr auto and_then(F &&f) &; template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(std::declval(), std::forward(f))) { return and_then_impl(*this, std::forward(f)); } - - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &&; template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype( and_then_impl(std::declval(), std::forward(f))) { return and_then_impl(std::move(*this), std::forward(f)); } - - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &; template constexpr auto and_then(F &&f) const & -> decltype( and_then_impl(std::declval(), std::forward(f))) { @@ -1342,8 +1287,6 @@ public: } #ifndef TL_EXPECTED_NO_CONSTRR - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; template constexpr auto and_then(F &&f) const && -> decltype( and_then_impl(std::declval(), std::forward(f))) { @@ -1354,7 +1297,6 @@ public: #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// Carries out some operation on the stored object if there is one. template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { return expected_map_impl(*this, std::forward(f)); } @@ -1368,7 +1310,6 @@ public: return expected_map_impl(std::move(*this), std::forward(f)); } #else - /// Carries out some operation on the stored object if there is one. template TL_EXPECTED_11_CONSTEXPR decltype( expected_map_impl(std::declval(), std::declval())) @@ -1400,7 +1341,6 @@ public: #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// Carries out some operation on the stored object if there is one. template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { return expected_map_impl(*this, std::forward(f)); } @@ -1414,8 +1354,7 @@ public: return expected_map_impl(std::move(*this), std::forward(f)); } #else - /// Carries out some operation on the stored object if there is one. - template + template TL_EXPECTED_11_CONSTEXPR decltype( expected_map_impl(std::declval(), std::declval())) transform(F &&f) & { @@ -1446,67 +1385,31 @@ public: #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// \brief Carries out some operation on the stored unexpected object if there - /// is one. - /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. If `U` is `void`, returns an `expected`, otherwise - /// returns an `expected`. If `*this` has an expected - /// value, the result is `*this`, otherwise an `expected` is constructed - /// from `make_unexpected(std::invoke(std::forward(f), value()))` and is - /// returned. - /// - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) &; template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { return map_error_impl(*this, std::forward(f)); } - - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) &&; template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { return map_error_impl(std::move(*this), std::forward(f)); } - - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) const &; template constexpr auto map_error(F &&f) const & { return map_error_impl(*this, std::forward(f)); } - - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) const &&; template constexpr auto map_error(F &&f) const && { return map_error_impl(std::move(*this), std::forward(f)); } #else - /// \brief Carries out some operation on the stored unexpected object if there - /// is one. - /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. Returns an `expected`. If `*this` has an expected - /// value, the result is `*this`, otherwise an `expected` is constructed - /// from `make_unexpected(std::invoke(std::forward(f), value()))` and is - /// returned. - /// - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) &; template TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), std::declval())) map_error(F &&f) & { return map_error_impl(*this, std::forward(f)); } - - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) &&; template TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), std::declval())) map_error(F &&f) && { return map_error_impl(std::move(*this), std::forward(f)); } - - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) const &; template constexpr decltype(map_error_impl(std::declval(), std::declval())) @@ -1515,8 +1418,6 @@ public: } #ifndef TL_EXPECTED_NO_CONSTRR - /// \group map_error - /// \synopsis template constexpr auto map_error(F &&f) const &&; template constexpr decltype(map_error_impl(std::declval(), std::declval())) @@ -1525,15 +1426,6 @@ public: } #endif #endif - - /// \brief Calls `f` if the expectd is in the unexpected state - /// \requires `F` is invokable with `E`, and `std::invoke_result_t` - /// must be void or convertible to `expcted`. - /// \effects If `*this` has a value, returns `*this`. - /// Otherwise, if `f` returns `void`, calls `std::forward(f)(E)` and returns - /// `std::nullopt`. Otherwise, returns `std::forward(f)(E)`. - /// - /// \group or_else template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { return or_else_impl(*this, std::forward(f)); } @@ -1571,8 +1463,6 @@ public: : impl_base(in_place, il, std::forward(args)...), ctor_base(detail::default_constructor_tag{}) {} - /// \group unexpected_ctor - /// \synopsis EXPLICIT constexpr expected(const unexpected &e); template ::value> * = nullptr, @@ -1582,8 +1472,7 @@ public: : impl_base(unexpect, e.value()), ctor_base(detail::default_constructor_tag{}) {} - /// \exclude - template < + template < class G = E, detail::enable_if_t::value> * = nullptr, @@ -1592,8 +1481,6 @@ public: : impl_base(unexpect, e.value()), ctor_base(detail::default_constructor_tag{}) {} - /// \group unexpected_ctor - /// \synopsis EXPLICIT constexpr expected(unexpected &&e); template < class G = E, detail::enable_if_t::value> * = nullptr, @@ -1603,8 +1490,7 @@ public: : impl_base(unexpect, std::move(e.value())), ctor_base(detail::default_constructor_tag{}) {} - /// \exclude - template < + template < class G = E, detail::enable_if_t::value> * = nullptr, detail::enable_if_t::value> * = nullptr> @@ -1620,8 +1506,7 @@ public: : impl_base(unexpect, std::forward(args)...), ctor_base(detail::default_constructor_tag{}) {} - /// \exclude - template &, Args &&...>::value> * = nullptr> constexpr explicit expected(unexpect_t, std::initializer_list il, @@ -1644,8 +1529,7 @@ public: } } - /// \exclude - template ::value && std::is_convertible::value)> * = nullptr, @@ -1674,8 +1558,7 @@ public: } } - /// \exclude - template < + template < class U, class G, detail::enable_if_t<(std::is_convertible::value && std::is_convertible::value)> * = nullptr, @@ -1696,8 +1579,7 @@ public: explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) : expected(in_place, std::forward(v)) {} - /// \exclude - template < + template < class U = T, detail::enable_if_t::value> * = nullptr, detail::expected_enable_forward_value * = nullptr> @@ -1728,8 +1610,7 @@ public: return *this; } - /// \exclude - template < + template < class U = T, class G = T, detail::enable_if_t::value> * = nullptr, @@ -1807,8 +1688,7 @@ public: } } - /// \exclude - template ::value> * = nullptr> void emplace(Args &&... args) { if (has_value()) { @@ -1846,8 +1726,7 @@ public: } } - /// \exclude - template &, Args &&...>::value> * = nullptr> void emplace(std::initializer_list il, Args &&... args) { @@ -1983,50 +1862,33 @@ public: } } - /// \returns a pointer to the stored value - /// \requires a value is stored - /// \group pointer constexpr const T *operator->() const { return valptr(); } - /// \group pointer TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); } - /// \returns the stored value - /// \requires a value is stored - /// \group deref template ::value> * = nullptr> constexpr const U &operator*() const & { return val(); } - /// \group deref template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR U &operator*() & { return val(); } - /// \group deref template ::value> * = nullptr> constexpr const U &&operator*() const && { return std::move(val()); } - /// \group deref template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR U &&operator*() && { return std::move(val()); } - /// \returns whether or not the optional has a value - /// \group has_value constexpr bool has_value() const noexcept { return this->m_has_val; } - /// \group has_value constexpr explicit operator bool() const noexcept { return this->m_has_val; } - /// \returns the contained value if there is one, otherwise throws - /// [bad_expected_access] - /// - /// \group value template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR const U &value() const & { @@ -2034,7 +1896,6 @@ public: detail::throw_exception(bad_expected_access(err().value())); return val(); } - /// \group value template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR U &value() & { @@ -2042,7 +1903,6 @@ public: detail::throw_exception(bad_expected_access(err().value())); return val(); } - /// \group value template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR const U &&value() const && { @@ -2050,7 +1910,6 @@ public: detail::throw_exception(bad_expected_access(err().value())); return std::move(val()); } - /// \group value template ::value> * = nullptr> TL_EXPECTED_11_CONSTEXPR U &&value() && { @@ -2059,26 +1918,17 @@ public: return std::move(val()); } - /// \returns the unexpected value - /// \requires there is an unexpected value - /// \group error constexpr const E &error() const & { return err().value(); } - /// \group error TL_EXPECTED_11_CONSTEXPR E &error() & { return err().value(); } - /// \group error constexpr const E &&error() const && { return std::move(err().value()); } - /// \group error TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(err().value()); } - /// \returns the stored value if there is one, otherwise returns `u` - /// \group value_or template constexpr T value_or(U &&v) const & { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy-constructible and convertible to from U&&"); return bool(*this) ? **this : static_cast(std::forward(v)); } - /// \group value_or template TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, @@ -2087,7 +1937,6 @@ public: } }; -/// \exclude namespace detail { template using exp_t = typename detail::decay_t::value_type; template using err_t = typename detail::decay_t::error_type;