diff --git a/expected.hpp b/expected.hpp index c9dda07..58452db 100644 --- a/expected.hpp +++ b/expected.hpp @@ -921,9 +921,9 @@ public: /// \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 a `std::expected` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward(f), value())`. Returns a - /// `std::expected`. The return value is empty if `*this` is empty, + /// 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) &; @@ -975,9 +975,9 @@ public: /// \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 a `std::expected` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward(f), value())`. Returns a - /// `std::expected`. The return value is empty if `*this` is empty, + /// 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) &; @@ -1034,7 +1034,8 @@ public: !defined(TL_EXPECTED_GCC54) /// \brief Carries out some operation on the stored object if there is one. /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. Returns a `std::expected`. If `*this` is unexpected, the + /// value())`. If `U` is `void`, returns an `expected, otherwise + // returns an `expected`. If `*this` is unexpected, the /// result is `*this`, otherwise an `expected` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. @@ -1065,7 +1066,8 @@ public: #else /// \brief Carries out some operation on the stored object if there is one. /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. Returns a `std::expected`. If `*this` is unexpected, the + /// value())`. If `U` is `void`, returns an `expected, otherwise + // returns an `expected`. If `*this` is unexpected, the /// result is `*this`, otherwise an `expected` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. @@ -1114,7 +1116,8 @@ public: /// \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 a `std::expected`. If `*this` has an expected + /// 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. @@ -1146,7 +1149,7 @@ public: /// \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 a `std::expected`. If `*this` has an expected + /// 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. @@ -1622,6 +1625,7 @@ public: /// \exclude namespace detail { +template using exp_t = typename detail::decay_t::error_type; template using err_t = typename detail::decay_t::error_type; template using ret_t = expected>; @@ -1683,19 +1687,35 @@ auto map_impl(Exp &&exp, F &&f) -> expected> { !defined(TL_EXPECTED_GCC54) template (), - *std::declval()))> + *std::declval())), + detail::enable_if_t::value> * = nullptr> constexpr auto map_error_impl(Exp &&exp, F &&f) { - using result = ret_t; + using result = expected, Ret>; return exp.has_value() ? result(*std::forward(exp)) : result(unexpect, detail::invoke(std::forward(f), std::forward(exp).error())); } +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), + std::forward(exp).error()); + return result(unexpect, monostate{}); +} #else template (), - *std::declval()))> -constexpr auto map_error_impl(Exp &&exp, F &&f) -> ret_t { + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected, Ret> { using result = ret_t; return exp.has_value() @@ -1703,6 +1723,21 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) -> ret_t { : result(unexpect, detail::invoke(std::forward(f), std::forward(exp).error())); } + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), + std::forward(exp).error()); + return result(unexpect, monostate{}); +} #endif template e = 21; + auto ret = e.map_error(ret_void); + REQUIRE(ret); + } + + { + const tl::expected e = 21; + auto ret = e.map_error(ret_void); + REQUIRE(ret); + } + + { + tl::expected e = 21; + auto ret = std::move(e).map_error(ret_void); + REQUIRE(ret); + } + + { + const tl::expected e = 21; + auto ret = std::move(e).map_error(ret_void); + REQUIRE(ret); + } + + { + tl::expected e(tl::unexpect, 21); + auto ret = e.map_error(ret_void); + REQUIRE(!ret); + } + + { + const tl::expected e(tl::unexpect, 21); + auto ret = e.map_error(ret_void); + REQUIRE(!ret); + } + + { + tl::expected e(tl::unexpect, 21); + auto ret = std::move(e).map_error(ret_void); + REQUIRE(!ret); + } + + { + const tl::expected e(tl::unexpect, 21); + auto ret = std::move(e).map_error(ret_void); + REQUIRE(!ret); + } } TEST_CASE("And then extensions", "[extensions.and_then]") {