From ed59461e583294af3a62d6244d98ef895fa9f2e4 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Thu, 30 Nov 2023 16:24:25 +0800 Subject: [PATCH] Revise pointer requirements --- proxy.h | 41 +++++++++++++++++++----------------- tests/proxy_traits_tests.cpp | 2 +- tests/utils.h | 2 +- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/proxy.h b/proxy.h index 9238a66..6f6cbff 100644 --- a/proxy.h +++ b/proxy.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -58,10 +59,12 @@ consteval bool has_destructibility(constraint_level level) { } } -template struct pointer_traits : inapplicable_traits {}; -template requires(requires(const P& ptr) { { *ptr }; }) -struct pointer_traits

: applicable_traits - { using value_type = decltype(*std::declval()); }; +// As per std::to_address() wording in [pointer.conversion] +template +concept is_address_deducible = + (std::is_pointer_v

&& !std::is_function_v>) || + requires(P p) { std::pointer_traits

::to_address(p); } || + requires(P p) { p.operator->(); }; template struct contains_traits : inapplicable_traits {}; template @@ -96,15 +99,16 @@ struct overload_traits : applicable_traits { using dispatcher_type = R (*)(const char*, Args...); template struct resolver { T operator()(Args...); }; - template - static constexpr bool applicable_operand = requires(T operand, Args... args) - { { D{}(std::forward(operand), std::forward(args)...) }; }; template - static R dispatcher(const char* p, Args... args) { + static constexpr bool applicable_pointer = requires(const P& p, Args... args) + { { D{}(*std::to_address(p), std::forward(args)...) }; }; + template + static R dispatcher(const char* erased, Args... args) { + const P& p = *reinterpret_cast(erased); if constexpr (std::is_void_v) { - D{}(**reinterpret_cast(p), std::forward(args)...); + D{}(*std::to_address(p), std::forward(args)...); } else { - return D{}(**reinterpret_cast(p), std::forward(args)...); + return D{}(*std::to_address(p), std::forward(args)...); } } }; @@ -137,9 +141,9 @@ struct dispatch_traits_impl> : applicable_traits, using dispatcher_types = std::tuple::dispatcher_type...>; - template - static constexpr bool applicable_operand = - (overload_traits::template applicable_operand && ...); + template + static constexpr bool applicable_pointer = + (overload_traits::template applicable_pointer && ...); template static constexpr dispatcher_types dispatchers{ overload_traits::template dispatcher...}; @@ -254,8 +258,7 @@ struct facade_traits_impl> : applicable_traits { has_copyability

(F::minimum_copyability) && has_relocatability

(F::minimum_relocatability) && has_destructibility

(F::minimum_destructibility) && - (dispatch_traits::template applicable_operand< - typename pointer_traits

::value_type> && ...) && + (dispatch_traits::template applicable_pointer

&& ...) && (std::is_void_v || std::is_constructible_v< typename F::reflection_type, std::in_place_type_t

>); template static constexpr meta_type meta{std::in_place_type

}; @@ -270,7 +273,7 @@ using dependent_t = typename dependent_traits::type; } // namespace details template -concept proxiable = details::pointer_traits

::applicable && +concept proxiable = details::is_address_deducible && details::basic_facade_traits::applicable && details::facade_traits::applicable && details::facade_traits::template applicable_pointer

; @@ -505,7 +508,7 @@ class sbo_ptr { sbo_ptr(sbo_ptr&&) noexcept(std::is_nothrow_move_constructible_v) = default; - T& operator*() const { return value_; } + T* operator->() const noexcept { return &value_; } private: mutable T value_; @@ -518,11 +521,11 @@ class deep_ptr { deep_ptr(Args&&... args) requires(std::is_constructible_v) : ptr_(new T(std::forward(args)...)) {} deep_ptr(const deep_ptr& rhs) requires(std::is_copy_constructible_v) - : ptr_(rhs.ptr_ == nullptr ? nullptr : new T(*rhs)) {} + : ptr_(rhs.ptr_ == nullptr ? nullptr : new T(*rhs.ptr_)) {} deep_ptr(deep_ptr&& rhs) noexcept : ptr_(rhs.ptr_) { rhs.ptr_ = nullptr; } ~deep_ptr() noexcept { delete ptr_; } - T& operator*() const { return *ptr_; } + T* operator->() const noexcept { return ptr_; } private: T* ptr_; diff --git a/tests/proxy_traits_tests.cpp b/tests/proxy_traits_tests.cpp index fb19112..f8c2a2a 100644 --- a/tests/proxy_traits_tests.cpp +++ b/tests/proxy_traits_tests.cpp @@ -14,7 +14,7 @@ struct MockPtr { MockPtr(const MockPtr&) noexcept requires(kTrivial) = default; MockPtr(MockPtr&&) noexcept requires(kNothrowRelocatable && !kTrivial) {} MockPtr(MockPtr&&) noexcept requires(kTrivial) = default; - const MockPtr& operator*() const noexcept { return *this; } + const MockPtr* operator->() const noexcept { return this; } alignas(kAlignment) char dummy_[kSize]; }; diff --git a/tests/utils.h b/tests/utils.h index 412dc73..aa7e45b 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -54,7 +54,7 @@ class LifetimeTracker { id_(rhs.host_->AllocateId(LifetimeOperationType::kMoveConstruction)), host_(rhs.host_) {} ~Session() { host_->ops_.emplace_back(id_, LifetimeOperationType::kDestruction); } - const Session& operator*() const { return *this; } + const Session* operator->() const { return this; } friend std::string to_string(const Session& self) { return "Session " + std::to_string(self.id_); } private: