diff --git a/include/pfn/expected.hpp b/include/pfn/expected.hpp index 2543483..962c223 100644 --- a/include/pfn/expected.hpp +++ b/include/pfn/expected.hpp @@ -275,11 +275,33 @@ template class expected { rhs.set_ = true; } + constexpr T const &_value() const & + { + ASSERT(set_); + return v_; + } + constexpr T &_value() & + { + ASSERT(set_); + return v_; + } + constexpr T const &&_value() const && + { + ASSERT(set_); + return ::std::move(v_); + } + constexpr T &&_value() && + { + ASSERT(set_); + return ::std::move(v_); + } + template static constexpr auto _and_then(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v && ::std::is_nothrow_constructible_v) - requires(::std::is_constructible_v) + requires(::std::is_invocable_v + && ::std::is_constructible_v) { using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(detail::_is_some_expected); @@ -293,14 +315,15 @@ template class expected { template static constexpr auto _or_else(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v) - requires(::std::is_constructible_v) + && ::std::is_nothrow_constructible_v) + requires(::std::is_invocable_v + && ::std::is_constructible_v) { using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(detail::_is_some_expected); static_assert(::std::is_same_v::value_type>); if (self.has_value()) { - return result_t(::std::in_place, FWD(self).value()); + return result_t(::std::in_place, FWD(self)._value()); } return ::std::invoke(FWD(fn), FWD(self).error()); } @@ -313,7 +336,8 @@ template class expected { || ::std::is_nothrow_constructible_v< ::std::remove_cv_t<::std::invoke_result_t>, ::std::invoke_result_t>)) - requires(::std::is_constructible_v) + requires(::std::is_invocable_v + && ::std::is_constructible_v) { using value_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_expected); @@ -333,11 +357,12 @@ template class expected { template static constexpr auto _transform_error(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v + && ::std::is_nothrow_constructible_v && ::std::is_nothrow_constructible_v< ::std::remove_cv_t<::std::invoke_result_t>, ::std::invoke_result_t>) - requires(::std::is_constructible_v) + requires(::std::is_invocable_v + && ::std::is_constructible_v) { using error_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_unexpected); @@ -346,7 +371,7 @@ template class expected { if (not self.has_value()) { return result_t(unexpect, ::std::invoke(FWD(fn), FWD(self).error())); } - return result_t(::std::in_place, FWD(self).value()); + return result_t(::std::in_place, FWD(self)._value()); } public: @@ -962,7 +987,7 @@ class expected { template static constexpr auto _and_then(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v && ::std::is_nothrow_constructible_v) - requires(::std::is_constructible_v) + requires(::std::is_invocable_v && ::std::is_constructible_v) { using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(detail::_is_some_expected); @@ -976,6 +1001,7 @@ class expected { template static constexpr auto _or_else(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v) + requires(::std::is_invocable_v) { using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(detail::_is_some_expected); @@ -992,7 +1018,7 @@ class expected { && (::std::is_void_v<::std::invoke_result_t> || ::std::is_nothrow_constructible_v<::std::remove_cv_t<::std::invoke_result_t>, ::std::invoke_result_t>)) - requires(::std::is_constructible_v) + requires(::std::is_invocable_v && ::std::is_constructible_v) { using value_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_expected); @@ -1015,6 +1041,7 @@ class expected { && ::std::is_nothrow_constructible_v< ::std::remove_cv_t<::std::invoke_result_t>, ::std::invoke_result_t>) + requires(::std::is_invocable_v) { using error_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_unexpected); diff --git a/tests/pfn/expected.cpp b/tests/pfn/expected.cpp index f808df4..3fcdbb1 100644 --- a/tests/pfn/expected.cpp +++ b/tests/pfn/expected.cpp @@ -26,6 +26,7 @@ using std::unexpected; #include #include +#include #include #include #include @@ -2509,6 +2510,15 @@ TEST_CASE("expected non void", "[expected][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(std::in_place, std::make_unique(42)); + static_assert(std::is_same_v &&>); + auto res = std::move(e).and_then([](T p) -> expected { return *p + 1; }); + CHECK(res.value() == 43); + } } SECTION("or_else") @@ -2569,6 +2579,14 @@ TEST_CASE("expected non void", "[expected][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(unexpect, std::make_unique(42)); + auto res = std::move(e).or_else([](T p) -> expected { return unexpected(*p + 1); }); + CHECK(res.error() == 43); + } } SECTION("transform") @@ -2628,6 +2646,14 @@ TEST_CASE("expected non void", "[expected][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(std::in_place, std::make_unique(42)); + auto res = std::move(e).transform([](T p) { return *p + 1; }); + CHECK(res.value() == 43); + } } SECTION("transform_error") @@ -2685,6 +2711,14 @@ TEST_CASE("expected non void", "[expected][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(unexpect, std::make_unique(42)); + auto res = std::move(e).transform_error([](T p) { return *p + 1; }); + CHECK(res.error() == 43); + } } } @@ -4223,6 +4257,14 @@ TEST_CASE("expected void", "[expected_void][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(unexpect, std::make_unique(42)); + auto res = std::move(e).or_else([](T p) -> expected { return unexpected(*p + 1); }); + CHECK(res.error() == 43); + } } SECTION("transform") @@ -4332,6 +4374,14 @@ TEST_CASE("expected void", "[expected_void][polyfill]") SUCCEED(); } } + + SECTION("move-only type") + { + using T = std::unique_ptr; + expected e(unexpect, std::make_unique(42)); + auto res = std::move(e).transform_error([](T p) { return *p + 1; }); + CHECK(res.error() == 43); + } } }