diff --git a/docs/spec/proxy/.pages b/docs/spec/proxy/.pages index 17deb330..3ac7fd10 100644 --- a/docs/spec/proxy/.pages +++ b/docs/spec/proxy/.pages @@ -9,7 +9,6 @@ nav: - operator= (non-member): friend_operator_equality.md - operator=: assignment.md - reflect (non-member): friend_reflect.md - - reinterpret_invoke (non-member): friend_reinterpret_invoke.md - reset: reset.md - swap (non-member): friend_swap.md - swap: swap.md diff --git a/docs/spec/proxy/README.md b/docs/spec/proxy/README.md index 5e56583f..6a1895f6 100644 --- a/docs/spec/proxy/README.md +++ b/docs/spec/proxy/README.md @@ -45,7 +45,6 @@ As per `facade`, `typename F::convention_types` shall be a [tuple-like](https | [`swap`](friend_swap.md) | overload the [`std::swap`](https://en.cppreference.com/w/cpp/algorithm/swap) algorithm | | [`invoke`](friend_invoke.md) | invokes a `proxy` with a specified convention | | [`reflect`](friend_reflect.md) | acquires reflection information of a contained type | -| [`reinterpret_invoke`](friend_reinterpret_invoke.md) | invokes a dispatch on a `proxy` whose contained type is known statically | ## Comparing with Other Standard Polymorphic Wrappers diff --git a/docs/spec/proxy/friend_invoke.md b/docs/spec/proxy/friend_invoke.md index be6fd290..a770392c 100644 --- a/docs/spec/proxy/friend_invoke.md +++ b/docs/spec/proxy/friend_invoke.md @@ -60,4 +60,3 @@ int main() { ## See Also - [function template `reflect` (`proxy`)](friend_reflect.md) -- [function template `reinterpret_invoke` (`proxy`)](friend_reinterpret_invoke.md) diff --git a/docs/spec/proxy/friend_reinterpret_invoke.md b/docs/spec/proxy/friend_reinterpret_invoke.md deleted file mode 100644 index ee988693..00000000 --- a/docs/spec/proxy/friend_reinterpret_invoke.md +++ /dev/null @@ -1,60 +0,0 @@ -# Function template `reinterpret_invoke` (`proxy`) - -> Since: 4.1.0 - -```cpp -template -R reinterpret_invoke(proxy& p, Args&&... args); -template -R reinterpret_invoke(const proxy& p, Args&&... args); -template -R reinterpret_invoke(proxy&& p, Args&&... args); -template -R reinterpret_invoke(const proxy&& p, Args&&... args); -``` - -Invokes a dispatch on the value contained in a `proxy`, reinterpreting the underlying storage as a caller-specified pointer type `P`. `D` is a dispatch type, `R` is the return type, and `Args...` are the argument types forwarded to the dispatch. - -Let `ptr` be the contained value of `p`, with the same cv ref-qualifiers as `p`. **The behavior is undefined unless `p` contains a value whose type is `P`.** Equivalent to [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D(), ptr, std::forward(args)...)`. - -This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy` is an associated class of the arguments. To reinterpret-invoke through the pointed-to value, use [`reinterpret_invoke`](../proxy_indirect_accessor/friend_reinterpret_invoke.md) on the associated [`proxy_indirect_accessor`](../proxy_indirect_accessor/README.md) (i.e., on `*p`). - -## Notes - -`reinterpret_invoke` is a low-level primitive. In contrast to [`invoke`](friend_invoke.md), it performs **no type erasure**: it neither consults the runtime metadata of the `proxy` nor requires `D` to correspond to a convention registered in `typename F::convention_types`. Instead, the caller names the exact contained pointer type `P`, and the implementation reinterprets the `proxy`'s storage as `P` directly. This avoids the indirection of a virtual call, at the cost of requiring the contained type to be known statically — supplying a `P` that does not match the contained value is undefined behavior. - -For ordinary use, prefer an [`accessor`](../ProAccessible.md) or [`invoke`](friend_invoke.md), which are type-erased and do not require the caller to know the contained type. `reinterpret_invoke` is intended for advanced scenarios, such as implementing custom dispatch types or [accessors](../ProAccessible.md), where the concrete pointer type is already known. - -## Example - -```cpp -#include -#include - -#include - -PRO_DEF_MEM_DISPATCH(MemUseCount, use_count); - -struct SharedAware - : pro::facade_builder // - ::add_direct_convention // - ::build {}; - -int main() { - pro::proxy p = - std::make_shared(123); // The contained pointer type is shared_ptr - - // Type-erased invocation via the runtime metadata of `p`: - std::cout << invoke(p) << "\n"; // "1" - - // Low-level invocation: we already know `p` holds a `std::shared_ptr`, - // so reinterpret the storage and dispatch directly, with no virtual call: - std::cout << reinterpret_invoke, MemUseCount, long>(p) - << "\n"; // Also prints "1" -} -``` - -## See Also - -- [function template `invoke` (`proxy`)](friend_invoke.md) -- [named requirements *ProDispatch*](../ProDispatch.md) diff --git a/docs/spec/proxy_indirect_accessor/.pages b/docs/spec/proxy_indirect_accessor/.pages index 8ae8f61e..d33f378a 100644 --- a/docs/spec/proxy_indirect_accessor/.pages +++ b/docs/spec/proxy_indirect_accessor/.pages @@ -2,4 +2,3 @@ nav: - proxy_indirect_accessor: README.md - invoke: friend_invoke.md - reflect: friend_reflect.md - - reinterpret_invoke: friend_reinterpret_invoke.md diff --git a/docs/spec/proxy_indirect_accessor/README.md b/docs/spec/proxy_indirect_accessor/README.md index fbab8dca..942863cc 100644 --- a/docs/spec/proxy_indirect_accessor/README.md +++ b/docs/spec/proxy_indirect_accessor/README.md @@ -27,7 +27,6 @@ Class template `proxy_indirect_accessor` provides indirection accessibility for | ---------------------------------------------------- | ------------------------------------------------------------ | | [`invoke`](friend_invoke.md) | invokes a `proxy` with a specified convention | | [`reflect`](friend_reflect.md) | acquires reflection information of a contained type | -| [`reinterpret_invoke`](friend_reinterpret_invoke.md) | invokes a dispatch on a `proxy` whose contained type is known statically | ## See also diff --git a/docs/spec/proxy_indirect_accessor/friend_invoke.md b/docs/spec/proxy_indirect_accessor/friend_invoke.md index 0a5e9f1c..e7d60f01 100644 --- a/docs/spec/proxy_indirect_accessor/friend_invoke.md +++ b/docs/spec/proxy_indirect_accessor/friend_invoke.md @@ -59,4 +59,3 @@ int main() { ## See Also - [function template `reflect` (`proxy_indirect_accessor`)](friend_reflect.md) -- [function template `reinterpret_invoke` (`proxy_indirect_accessor`)](friend_reinterpret_invoke.md) diff --git a/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md b/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md deleted file mode 100644 index 0d0ca6c0..00000000 --- a/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md +++ /dev/null @@ -1,60 +0,0 @@ -# Function template `reinterpret_invoke` (`proxy_indirect_accessor`) - -> Since: 4.1.0 - -```cpp -template -R reinterpret_invoke(proxy_indirect_accessor& p, Args&&... args); -template -R reinterpret_invoke(const proxy_indirect_accessor& p, Args&&... args); -template -R reinterpret_invoke(proxy_indirect_accessor&& p, Args&&... args); -template -R reinterpret_invoke(const proxy_indirect_accessor&& p, Args&&... args); -``` - -Invokes a dispatch on the value contained in the associated `proxy`, reinterpreting the underlying storage as a caller-specified pointer type `P`. `D` is a dispatch type, `R` is the return type, and `Args...` are the argument types forwarded to the dispatch. - -Let `ptr` be the contained value of the `proxy` object associated to `p`, with the same cv ref-qualifiers as `p`. **The behavior is undefined unless the associated `proxy` contains a value whose type is `P`.** Equivalent to [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D(), *ptr, std::forward(args)...)`. - -This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy_indirect_accessor` is an associated class of the arguments. To reinterpret-invoke on the contained pointer itself, use [`reinterpret_invoke`](../proxy/friend_reinterpret_invoke.md) on the [`proxy`](../proxy/README.md). - -## Notes - -`reinterpret_invoke` is a low-level primitive. In contrast to [`invoke`](friend_invoke.md), it performs **no type erasure**: it neither consults the runtime metadata of the `proxy` nor requires `D` to correspond to a convention registered in `typename F::convention_types`. Instead, the caller names the exact contained pointer type `P`, and the implementation reinterprets the `proxy`'s storage as `P` directly. This avoids the indirection of a virtual call, at the cost of requiring the contained type to be known statically. Supplying a `P` that does not match the contained value is undefined behavior. - -For ordinary use, prefer an [`accessor`](../ProAccessible.md) or [`invoke`](friend_invoke.md), which are type-erased and do not require the caller to know the contained type. `reinterpret_invoke` is intended for advanced scenarios, such as implementing custom dispatch types or [accessors](../ProAccessible.md), where the concrete pointer type is already known. - -## Example - -```cpp -#include -#include - -#include - -PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); - -struct Stringable : pro::facade_builder // - ::add_convention // - ::build {}; - -int main() { - int a = 123; - pro::proxy p = &a; // The contained pointer type is `int*` - - // Type-erased invocation via the runtime metadata of the associated proxy: - std::cout << invoke(*p) << "\n"; // "123" - - // Low-level invocation: we already know the proxy holds an `int*`, so - // reinterpret the storage as `int*` and dispatch directly, with no virtual - // call. The dispatch receives the pointed-to `int`: - std::cout << reinterpret_invoke(*p) - << "\n"; // Also prints "123" -} -``` - -## See Also - -- [function template `invoke` (`proxy_indirect_accessor`)](friend_invoke.md) -- [named requirements *ProDispatch*](../ProDispatch.md) diff --git a/include/proxy/v4/detail/core.h b/include/proxy/v4/detail/core.h index 00b87943..511ae960 100644 --- a/include/proxy/v4/detail/core.h +++ b/include/proxy/v4/detail/core.h @@ -59,6 +59,7 @@ template class proxy_indirect_accessor; template class PRO4D_ENFORCE_EBO proxy; +struct substitution_dispatch; template struct is_bitwise_trivially_relocatable @@ -211,23 +212,17 @@ template struct destructibility_traits : applicable_traits {}; -template -using proxy_accessor = add_qualifier_t< - std::conditional_t, proxy_indirect_accessor>, Q>; template add_qualifier_t, Q> as_proxy(add_qualifier_t, Q> p); struct proxy_helper { - template - struct resetting_guard { - explicit resetting_guard(proxy& p) noexcept : p_(p) {} - explicit resetting_guard(proxy_indirect_accessor& p) noexcept + template + struct meta_resetting_guard { + explicit meta_resetting_guard(proxy& p) noexcept : p_(p) {} + explicit meta_resetting_guard(proxy_indirect_accessor& p) noexcept : p_(as_proxy(p)) {} - ~resetting_guard() noexcept(std::is_nothrow_destructible_v

) { - std::destroy_at(std::addressof(get_ptr(p_))); - p_.meta_.reset(); - } + ~meta_resetting_guard() noexcept { p_.meta_.reset(); } private: proxy& p_; @@ -243,16 +238,29 @@ struct proxy_helper { get_meta(const proxy_indirect_accessor& p) noexcept { return get_meta(as_proxy(p)); } - template - static add_qualifier_t get_ptr(add_qualifier_t, Q> p) { - return static_cast>( - reinterpret_cast>(*std::launder(p.ptr_))); + template + static void* get_ptr(proxy& p) noexcept { + return p.ptr_; + } + template + static const void* get_ptr(const proxy& p) noexcept { + return p.ptr_; } - template - static void trivially_relocate(proxy& from, proxy& to) noexcept { - std::uninitialized_copy_n(from.ptr_, sizeof(P), to.ptr_); - to.meta_ = decltype(proxy::meta_){std::in_place_type

}; - from.meta_.reset(); + template + static void* get_ptr(proxy_indirect_accessor& p) noexcept { + return get_ptr(as_proxy(p)); + } + template + static const void* get_ptr(const proxy_indirect_accessor& p) noexcept { + return get_ptr(as_proxy(p)); + } + template + static proxy make_relocated(void* src) noexcept { + proxy ret; + std::uninitialized_copy_n(static_cast(src), sizeof(P), + ret.ptr_); + ret.meta_ = decltype(ret.meta_){std::in_place_type

}; + return ret; } }; @@ -275,14 +283,13 @@ concept invocable_dispatch = (Q != qualifier_type::rv || (NE && std::is_nothrow_destructible_v

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

)); -struct internal_dispatch {}; - template struct overload_traits : inapplicable_traits {}; template struct overload_traits_impl : applicable_traits { using return_type = R; + static constexpr qualifier_type this_qualifier = Q; template static constexpr bool applicable_ptr = invocable_dispatch; @@ -326,6 +333,121 @@ struct overload_traits template using ret_t = overload_traits::return_type; +template +operand_t + get_operand(std::remove_reference_t>* self) { + if constexpr (IsDirect) { + return static_cast>(*self); + } else { + add_qualifier_t ptr = static_cast>(*self); + if constexpr (std::is_constructible_v) { + assert(ptr); + } + return *std::forward>(ptr); + } +} + +// When a dispatch always throws, MSVC may incorrectly warn about unreachable +// code (C4702). Disable the warning for invoke_dispatch(). +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 4702) +#endif // defined(_MSC_VER) && !defined(__clang__) +template +R invoke_dispatch(Args&&... args) { + if constexpr (std::is_void_v) { + D()(std::forward(args)...); + } else { + return D()(std::forward(args)...); + } +} +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif // defined(_MSC_VER) && !defined(__clang__) + +template +struct destroying_guard { + explicit destroying_guard(P* p) noexcept : p_(p) {} + ~destroying_guard() noexcept(std::is_nothrow_destructible_v

) { + std::destroy_at(p_); + } + +private: + P* p_; +}; + +struct relocate_dispatch; + +template +struct erased_context { + static constexpr qualifier_type qualifier = + overload_traits::this_qualifier; + + template + friend ret_t invoke(erased_context ctx, Args&&... args) { + auto* self = std::launder( + static_cast>*>( + ctx.p_)); + if constexpr (qualifier == qualifier_type::rv) { + destroying_guard

guard{self}; + return invoke_dispatch>( + get_operand(self), + std::forward(args)...); + } else { + return invoke_dispatch>( + get_operand(self), + std::forward(args)...); + } + } + + std::conditional_t + p_; +}; +template +struct erased_context { + template + friend ret_t invoke(erased_context ctx, void* rhs) { + auto* self = std::launder(static_cast(ctx.p_)); + if constexpr (is_bitwise_trivially_relocatable_v

) { + if constexpr (!std::is_empty_v

) { + std::uninitialized_copy_n(reinterpret_cast(self), + sizeof(P), static_cast(rhs)); + } + } else { + destroying_guard

guard{self}; + std::construct_at(static_cast(rhs), std::move(*self)); + } + } + + void* p_; +}; +// TODO: remove together with substitution_dispatch. +#define PRO4D_DEF_SUBSTITUTION_CONTEXT(...) \ + template \ + struct erased_context() && __VA_ARGS__> { \ + template \ + friend proxy invoke(erased_context ctx) __VA_ARGS__ { \ + if constexpr (is_bitwise_trivially_relocatable_v

) { \ + return proxy_helper::make_relocated(ctx.p_); \ + } else { \ + auto* self = std::launder(static_cast(ctx.p_)); \ + destroying_guard

guard{self}; \ + return proxy{std::move(*self)}; \ + } \ + } \ + \ + void* p_; \ + } +PRO4D_DEF_SUBSTITUTION_CONTEXT(); +PRO4D_DEF_SUBSTITUTION_CONTEXT(noexcept); +#undef PRO4D_DEF_SUBSTITUTION_CONTEXT + +template +using erased_invoker_t = invoker, O>; + template struct overload_substitution_traits : inapplicable_traits { template @@ -398,9 +520,9 @@ template struct conv_traits_impl { static_assert((overload_traits>::applicable && ...)); - using meta = std::tuple, proxy_indirect_accessor>, - typename C::dispatch_type, substituted_overload_t>...>; + using meta = + std::tuple>...>; template using accessor = accessor_t - PRO4D_STATIC_CALL(void, const T& self, proxy& rhs) noexcept( + template + PRO4D_STATIC_CALL(void, const T& self, void* rhs) noexcept( std::is_nothrow_copy_constructible_v) { - std::construct_at(std::addressof(rhs), self); - } -}; -struct relocate_dispatch : internal_dispatch { - template - PRO4D_STATIC_CALL(void, std::in_place_type_t

, proxy&& self, - proxy& rhs) noexcept { - proxy_helper::trivially_relocate

(self, rhs); - } - template - PRO4D_STATIC_CALL(void, T&& self, proxy& rhs) noexcept( - relocatability_traits::applicable) { - std::construct_at(std::addressof(rhs), std::forward(self)); + std::construct_at(static_cast(rhs), self); } }; struct destroy_dispatch { @@ -485,16 +595,16 @@ struct destroy_dispatch { std::destroy_at(&self); } }; -template +template struct lifetime_meta_traits : std::type_identity {}; -template -struct lifetime_meta_traits - : std::type_identity, D, ONE>> {}; -template -struct lifetime_meta_traits - : std::type_identity, D, OE>> {}; -template -using lifetime_meta_t = lifetime_meta_traits::type; +template +struct lifetime_meta_traits + : std::type_identity> {}; +template +struct lifetime_meta_traits + : std::type_identity> {}; +template +using lifetime_meta_t = lifetime_meta_traits::type; template struct PRO4D_ENFORCE_EBO composite_accessor : As... {}; @@ -668,16 +778,15 @@ struct facade_traits : specialization_t { using meta_storage_base = specialization_t< compact_facade_meta_traits::storage, - composite_t< - std::tuple<>, - lifetime_meta_t&) const noexcept, - void(proxy&) const, F::copyability>, - lifetime_meta_t&) && noexcept, - void(proxy&) &&, F::relocatability>, - lifetime_meta_t, - typename facade_traits::conv_meta, - typename facade_traits::refl_meta>>; + composite_t, + lifetime_meta_t, + lifetime_meta_t, + lifetime_meta_t, + typename facade_traits::conv_meta, + typename facade_traits::refl_meta>>; using indirect_accessor = composite_t; @@ -737,12 +846,6 @@ class inplace_ptr { T value_; }; -template -ret_t invoke_impl(P&& p, Args&&... args) { - return proxy_helper::get_meta(p) - .template get, D, O>>()( - std::forward

(p), std::forward(args)...); -} template add_qualifier_t, Q> as_proxy(add_qualifier_t, Q> p) { @@ -750,57 +853,16 @@ add_qualifier_t, Q> reinterpret_cast< add_qualifier_t>, Q>>(p)); } -template -operand_t get_operand(proxy_accessor p) { - if constexpr (IsDirect) { - return proxy_helper::get_ptr( - std::forward>(p)); - } else { - add_qualifier_t ptr = proxy_helper::get_ptr( - as_proxy(std::forward>(p))); - if constexpr (std::is_constructible_v) { - assert(ptr); - } - return *std::forward>(ptr); - } -} - -// When a dispatch always throws, MSVC may incorrectly warn about unreachable -// code (C4702). Disable the warning for invoke_dispatch(). -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) -#pragma warning(disable : 4702) -#endif // defined(_MSC_VER) && !defined(__clang__) -template -R invoke_dispatch(Args&&... args) { - if constexpr (std::is_void_v) { - D()(std::forward(args)...); - } else { - return D()(std::forward(args)...); - } -} -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(pop) -#endif // defined(_MSC_VER) && !defined(__clang__) -template -R reinterpret_invoke(proxy_accessor self, Args&&... args) { - if constexpr (Q == qualifier_type::rv) { - if constexpr (std::is_base_of_v && - is_bitwise_trivially_relocatable_v

) { - return D()(std::in_place_type

, std::move(self), - std::forward(args)...); - } else { - proxy_helper::resetting_guard guard{self}; - return invoke_dispatch( - get_operand(std::move(self)), - std::forward(args)...); - } +template +ret_t invoke_impl(P&& p, Args&&... args) { + using Ctx = erased_context; + Ctx ctx{proxy_helper::get_ptr(p)}; + const auto& inv = proxy_helper::get_meta(p).template get>(); + if constexpr (overload_traits::this_qualifier == qualifier_type::rv) { + proxy_helper::meta_resetting_guard guard{p}; + return inv(ctx, std::forward(args)...); } else { - return invoke_dispatch( - get_operand( - std::forward>(self)), - std::forward(args)...); + return inv(ctx, std::forward(args)...); } } @@ -821,46 +883,23 @@ class proxy_indirect_accessor public: template friend detail::ret_t invoke(proxy_indirect_accessor& p, Args&&... args) { - return detail::invoke_impl(p, std::forward(args)...); + return detail::invoke_impl(p, std::forward(args)...); } template friend detail::ret_t invoke(const proxy_indirect_accessor& p, Args&&... args) { - return detail::invoke_impl(p, std::forward(args)...); + return detail::invoke_impl(p, std::forward(args)...); } template friend detail::ret_t invoke(proxy_indirect_accessor&& p, Args&&... args) { - return detail::invoke_impl(std::move(p), std::forward(args)...); + return detail::invoke_impl(std::move(p), + std::forward(args)...); } template friend detail::ret_t invoke(const proxy_indirect_accessor&& p, Args&&... args) { - return detail::invoke_impl(std::move(p), std::forward(args)...); - } - template - friend R reinterpret_invoke(proxy_indirect_accessor& p, Args&&... args) { - return detail::reinterpret_invoke(p, std::forward(args)...); - } - template - friend R reinterpret_invoke(const proxy_indirect_accessor& p, - Args&&... args) { - return detail::reinterpret_invoke( - p, std::forward(args)...); - } - template - friend R reinterpret_invoke(proxy_indirect_accessor&& p, Args&&... args) { - return detail::reinterpret_invoke(std::move(p), - std::forward(args)...); - } - template - friend R reinterpret_invoke(const proxy_indirect_accessor&& p, - Args&&... args) { - return detail::reinterpret_invoke( - std::move(p), std::forward(args)...); + return detail::invoke_impl(std::move(p), + std::forward(args)...); } template friend const R& reflect(const proxy_indirect_accessor& p) noexcept { @@ -1064,42 +1103,21 @@ class proxy : public detail::facade_traits::direct_accessor, } template friend detail::ret_t invoke(proxy& p, Args&&... args) { - return detail::invoke_impl(p, std::forward(args)...); + return detail::invoke_impl(p, std::forward(args)...); } template friend detail::ret_t invoke(const proxy& p, Args&&... args) { - return detail::invoke_impl(p, std::forward(args)...); + return detail::invoke_impl(p, std::forward(args)...); } template friend detail::ret_t invoke(proxy&& p, Args&&... args) { - return detail::invoke_impl(std::move(p), std::forward(args)...); + return detail::invoke_impl(std::move(p), + std::forward(args)...); } template friend detail::ret_t invoke(const proxy&& p, Args&&... args) { - return detail::invoke_impl(std::move(p), std::forward(args)...); - } - template - friend R reinterpret_invoke(proxy& p, Args&&... args) { - return detail::reinterpret_invoke(p, std::forward(args)...); - } - template - friend R reinterpret_invoke(const proxy& p, Args&&... args) { - return detail::reinterpret_invoke( - p, std::forward(args)...); - } - template - friend R reinterpret_invoke(proxy&& p, Args&&... args) { - return detail::reinterpret_invoke(std::move(p), - std::forward(args)...); - } - template - friend R reinterpret_invoke(const proxy&& p, Args&&... args) { - return detail::reinterpret_invoke( - std::move(p), std::forward(args)...); + return detail::invoke_impl(std::move(p), + std::forward(args)...); } template friend const R& reflect(const proxy& p) noexcept { @@ -1120,12 +1138,12 @@ class proxy : public detail::facade_traits::direct_accessor, if (rhs.meta_.has_value()) { if constexpr (F::copyability == constraint_level::trivial) { std::ranges::uninitialized_copy(rhs.ptr_, ptr_); - meta_ = rhs.meta_; } else { invoke(rhs, *this); + void(void*) const noexcept( + F::copyability == constraint_level::nothrow)>(rhs, ptr_); } + meta_ = rhs.meta_; } else { meta_.reset(); } @@ -1135,16 +1153,17 @@ class proxy : public detail::facade_traits::direct_accessor, { PRO4D_DEBUG(std::ignore = &pro_symbol_guard;) if (rhs.meta_.has_value()) { + auto meta = rhs.meta_; if constexpr (F::relocatability == constraint_level::trivial) { std::ranges::uninitialized_copy(rhs.ptr_, ptr_); - meta_ = rhs.meta_; rhs.meta_.reset(); } else { invoke( - std::move(rhs), *this); + std::move(rhs), ptr_); } + meta_ = meta; } else { meta_.reset(); } @@ -1182,8 +1201,8 @@ class proxy : public detail::facade_traits::direct_accessor, *std::move(cself); }) - detail::meta_storage meta_; alignas(F::max_align) std::byte ptr_[F::max_size]; + detail::meta_storage meta_; }; template @@ -1238,8 +1257,6 @@ template return reflect(p); } -struct substitution_dispatch; - template struct observer_facade; template @@ -1439,17 +1456,7 @@ using weak_conv_types = composite_t< } // namespace detail struct PRO4D_ENFORCE_EBO substitution_dispatch - : detail::cast_dispatch_base, - detail::internal_dispatch { - template - PRO4D_STATIC_CALL(auto, std::in_place_type_t

, proxy&& self) noexcept { - return detail::converter{ - [&self](std::in_place_type_t>) noexcept { - proxy ret; - detail::proxy_helper::trivially_relocate

(self, ret); - return ret; - }}; - } + : detail::cast_dispatch_base { template PRO4D_STATIC_CALL(T&&, T&& self) noexcept { return std::forward(self); diff --git a/include/proxy/v4/detail/facade_meta_traits.h b/include/proxy/v4/detail/facade_meta_traits.h index 5ae8157c..56d71b68 100644 --- a/include/proxy/v4/detail/facade_meta_traits.h +++ b/include/proxy/v4/detail/facade_meta_traits.h @@ -124,19 +124,18 @@ struct invoker_base { code_ptr p_; }; -template +template struct invoker; #define PRO4D_DEF_INVOKER(oq, pq, ne, ...) \ - template \ - struct invoker \ - : invoker_base { \ + template \ + struct invoker \ + : invoker_base { \ invoker() = default; \ template \ constexpr explicit invoker(std::in_place_type_t

) \ - : invoker_base( \ - [](ProP pq self, Args... args) ne -> R { \ - return reinterpret_invoke( \ - static_cast(self), std::forward(args)...); \ + : invoker_base( \ + [](Ctx ctx, Args... args) ne -> R { \ + return invoke

(ctx, std::forward(args)...); \ }) {} \ } PRO4D_DEF_OVERLOAD_SPECIALIZATIONS(PRO4D_DEF_INVOKER) @@ -235,16 +234,16 @@ struct flat_meta_storage_traits } // namespace detail struct compact_facade_meta_traits { - template - using invoker = detail::invoker; + template + using invoker = detail::invoker; template using storage = detail::compact_meta_storage_traits::type; }; struct flat_facade_meta_traits { - template - using invoker = detail::invoker; + template + using invoker = detail::invoker; template using storage = detail::flat_meta_storage_traits::type;