From 144ce4a0ce3d602e73333e71d2c533d7f0947062 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Sat, 15 Mar 2025 22:18:56 +0800 Subject: [PATCH] Align behavior of rvalue reference --- proxy.h | 88 ++++++++++++++------------------ tests/proxy_creation_tests.cpp | 1 + tests/proxy_invocation_tests.cpp | 2 + tests/proxy_rtti_tests.cpp | 3 +- 4 files changed, 42 insertions(+), 52 deletions(-) diff --git a/proxy.h b/proxy.h index 165c23e5..044ba181 100644 --- a/proxy.h +++ b/proxy.h @@ -198,25 +198,24 @@ class destruction_guard { T* p_; }; -template -struct ptr_traits : inapplicable_traits {}; -template - requires(requires { *std::declval>(); } && - (!NE || noexcept(*std::declval>()))) -struct ptr_traits : applicable_traits - { using target_type = decltype(*std::declval>()); }; +template +struct operand_traits : add_qualifier_traits {}; +template +struct operand_traits + : std::type_identity>())> {}; +template +using operand_t = typename operand_traits::type; template concept invocable_dispatch = (NE && std::is_nothrow_invocable_r_v< R, D, Args...>) || (!NE && std::is_invocable_r_v); -template -concept invocable_dispatch_ptr_indirect = ptr_traits::applicable && - invocable_dispatch< - D, NE, R, typename ptr_traits::target_type, Args...>; -template -concept invocable_dispatch_ptr_direct = invocable_dispatch< - D, NE, R, add_qualifier_t, Args...> && (Q != qualifier_type::rv || - (NE && std::is_nothrow_destructible_v

) || +template +concept invocable_dispatch_ptr = + (IsDirect || (requires { *std::declval>(); } && + (!NE || noexcept(*std::declval>())))) && + invocable_dispatch, Args...> && + (Q != qualifier_type::rv || (NE && std::is_nothrow_destructible_v

) || (!NE && std::is_destructible_v

)); template @@ -227,25 +226,27 @@ R invoke_dispatch(Args&&... args) { return D{}(std::forward(args)...); } } -template -R indirect_conv_dispatcher(add_qualifier_t self, Args... args) - noexcept(invocable_dispatch_ptr_indirect) { - auto& qp = *std::launder(reinterpret_cast>(&self)); - if constexpr (std::is_constructible_v) { assert(qp); } - return invoke_dispatch(*std::forward>(qp), - std::forward(args)...); +template +decltype(auto) get_operand(T& ptr) { + if constexpr (IsDirect) { + return std::forward>(ptr); + } else { + if constexpr (std::is_constructible_v) { assert(ptr); } + return *std::forward>(ptr); + } } -template -R direct_conv_dispatcher(add_qualifier_t self, Args... args) - noexcept(invocable_dispatch_ptr_direct) { +template +R conv_dispatcher(add_qualifier_t self, Args... args) + noexcept(invocable_dispatch_ptr) { auto& qp = *std::launder(reinterpret_cast>(&self)); if constexpr (Q == qualifier_type::rv) { destruction_guard guard{&qp}; - return invoke_dispatch( - std::forward>(qp), std::forward(args)...); + return invoke_dispatch(get_operand(qp), + std::forward(args)...); } else { - return invoke_dispatch( - std::forward>(qp), std::forward(args)...); + return invoke_dispatch(get_operand(qp), + std::forward(args)...); } } template @@ -263,28 +264,16 @@ struct overload_traits_impl : applicable_traits { template static consteval bool is_applicable_ptr() { - if constexpr (IsDirect) { - if constexpr (invocable_dispatch_ptr_direct) { - return true; - } else { - return invocable_dispatch; - } + if constexpr (invocable_dispatch_ptr) { + return true; } else { - if constexpr (invocable_dispatch_ptr_indirect) { - return true; - } else { - return invocable_dispatch; - } + return invocable_dispatch; } } template static consteval dispatcher_type get_dispatcher() { - if constexpr (!IsDirect && - invocable_dispatch_ptr_indirect) { - return &indirect_conv_dispatcher; - } else if constexpr (IsDirect && - invocable_dispatch_ptr_direct) { - return &direct_conv_dispatcher; + if constexpr (invocable_dispatch_ptr) { + return &conv_dispatcher; } else { return &default_conv_dispatcher; } @@ -791,8 +780,7 @@ struct proxy_helper { static decltype(auto) invoke(add_qualifier_t, Q> p, Args&&... args) { auto dispatcher = get_meta(p).template invocation_meta ::dispatcher; - if constexpr ( - IsDirect && overload_traits::qualifier == qualifier_type::rv) { + if constexpr (overload_traits::qualifier == qualifier_type::rv) { meta_ptr_reset_guard guard{p.meta_}; return dispatcher(std::forward>(*p.ptr_), std::forward(args)...); @@ -1327,8 +1315,8 @@ class strong_compact_ptr { return std::launder(reinterpret_cast(&this->ptr_->value)); } T& operator*() & noexcept { return *operator->(); } const T& operator*() const& noexcept { return *operator->(); } - T&& operator*() && noexcept { return std::move(operator->()); } - const T&& operator*() const&& noexcept { return std::move(operator->()); } + T&& operator*() && noexcept { return std::move(*operator->()); } + const T&& operator*() const&& noexcept { return std::move(*operator->()); } private: explicit strong_compact_ptr(Storage* ptr) noexcept diff --git a/tests/proxy_creation_tests.cpp b/tests/proxy_creation_tests.cpp index 8ab129d8..ad78f3f2 100644 --- a/tests/proxy_creation_tests.cpp +++ b/tests/proxy_creation_tests.cpp @@ -994,5 +994,6 @@ TEST(ProxyCreationTests, TestMakeProxyView) { ASSERT_EQ((*p)(), 0); ASSERT_EQ((*std::as_const(p))(), 1); ASSERT_EQ((*std::move(p))(), 2); + p = pro::make_proxy_view(test_callable); ASSERT_EQ((*std::move(std::as_const(p)))(), 3); } diff --git a/tests/proxy_invocation_tests.cpp b/tests/proxy_invocation_tests.cpp index 0aa12b5f..3610138e 100644 --- a/tests/proxy_invocation_tests.cpp +++ b/tests/proxy_invocation_tests.cpp @@ -333,6 +333,7 @@ TEST(ProxyInvocationTests, TestQualifiedConvention_Member) { ASSERT_EQ((*p)(), 0); ASSERT_EQ((*std::as_const(p))(), 1); ASSERT_EQ((*std::move(p))(), 2); + p = pro::make_proxy(); ASSERT_EQ((*std::move(std::as_const(p)))(), 3); } @@ -347,5 +348,6 @@ TEST(ProxyInvocationTests, TestQualifiedConvention_Free) { ASSERT_EQ(Dump(*p), "is_const=false, is_ref=true, value=123"); ASSERT_EQ(Dump(*std::as_const(p)), "is_const=true, is_ref=true, value=123"); ASSERT_EQ(Dump(*std::move(p)), "is_const=false, is_ref=false, value=123"); + p = pro::make_proxy(123); ASSERT_EQ(Dump(*std::move(std::as_const(p))), "is_const=true, is_ref=false, value=123"); } diff --git a/tests/proxy_rtti_tests.cpp b/tests/proxy_rtti_tests.cpp index 6a78b0eb..42b0b6fd 100644 --- a/tests/proxy_rtti_tests.cpp +++ b/tests/proxy_rtti_tests.cpp @@ -91,8 +91,7 @@ TEST(ProxyRttiTests, TestIndirectCast_Move_Succeed) { auto p = pro::make_proxy(v1); auto v2 = proxy_cast>(std::move(*p)); ASSERT_EQ(v2, v1); - v2 = proxy_cast>(std::move(*p)); - ASSERT_TRUE(v2.empty()); + ASSERT_FALSE(p.has_value()); } TEST(ProxyRttiTests, TestIndirectCast_Move_Fail) {