diff --git a/docs/PRO_DEF_WEAK_DISPATCH.md b/docs/PRO_DEF_WEAK_DISPATCH.md deleted file mode 100644 index 09714915..00000000 --- a/docs/PRO_DEF_WEAK_DISPATCH.md +++ /dev/null @@ -1,74 +0,0 @@ -# Macro `PRO_DEF_WEAK_DISPATCH` - -```cpp -#define PRO_DEF_WEAK_DISPATCH // deprecated since 3.2.0, see below -``` - -⚠️ Macro PRO_DEF_WEAK_DISPATCH has been replaced by class template weak_dispatch since 3.2, and may be removed in a future version. - -Macro `PRO_DEF_WEAK_DISPATCH` defines a "weak dispatch" type with a default implementation. It supports the following syntax: - -```cpp -PRO_DEF_WEAK_DISPATCH(dispatch_name, existing_dispatch, default_func_name); -``` - -Defines a class named `dispatch_name` that inherits `existing_dispatch` and provides additional overloads of `operator()` calling `default_func_name`. Effectively equivalent to: - -```cpp -struct dispatch_name : existing_dispatch { - using existing_dispatch::operator(); - template - decltype(auto) operator()(std::nullptr_t, Args&&... args) const - noexcept(noexcept(default_func_name(std::forward(args)...))) - requires(requires { default_func_name(std::forward(args)...); }) { - return default_func_name(std::forward(args)...); - } -} -``` - -## Notes - -A "weak dispatch" can extend an existing dispatch with a default implementation that does not depend on the contained value of a `proxy` object. This is useful when instantiating a `proxy` with a value that does not support some conventions defined by `F`. Similar to [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), `default_func_name` can be the name of an arbitrary function or anything that supports `()` syntax, including a constructor. Compared to wrapping the default implementation with [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), using "weak dispatch" when applicable can effectively improve compilation speed and binary size, in case some contained value of a `proxy` object does not participate code generation. - -In [Java](https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html#jls-9.4-200) or [C#](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods), a "default method" can invoke other abstract methods defined in a same `interface`. This pattern is discouraged when using the "Proxy" library because the invocations are not necessarily indirect. If a "default implementation" otherwise needs to observe the contained value of a `proxy` object, it is encouraged to define a separate free function, and subsequently define a dispatch type of it by using [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) or [`PRO_DEF_FREE_AS_MEM_DISPATCH`](PRO_DEF_FREE_AS_MEM_DISPATCH.md). - -## Example - -```cpp -#include -#include -#include - -#include "proxy.h" - -struct NotImplemented { - explicit NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; } - - template - operator T() const noexcept { std::terminate(); } // Or std::unreachable() in C++23 -}; - -PRO_DEF_MEM_DISPATCH(MemAt, at); -PRO_DEF_WEAK_DISPATCH(WeakMemAt, MemAt, NotImplemented); - -struct WeakDictionary : pro::facade_builder - ::add_convention - ::build {}; - -int main() { - std::vector v{"hello", "world"}; - pro::proxy p1 = &v; - std::cout << p1->at(1) << "\n"; // Prints "world" - pro::proxy p2 = pro::make_proxy(123); - try { - p2->at(1); - } catch (const std::runtime_error& e) { - std::cout << e.what() << "\n"; // Prints "Not implemented!" - } -} -``` - -## See Also - -- [class template `weak_dispatch`](weak_dispatch.md) -- [named requirements *ProDispatch*](ProDispatch.md) diff --git a/docs/basic_facade_builder/add_convention.md b/docs/basic_facade_builder/add_convention.md index 165ddc1a..7aa65c64 100644 --- a/docs/basic_facade_builder/add_convention.md +++ b/docs/basic_facade_builder/add_convention.md @@ -69,4 +69,3 @@ int main() { - [macro `PRO_DEF_FREE_DISPATCH`](../PRO_DEF_FREE_DISPATCH.md) - [class template `operator_dispatch`](../operator_dispatch.md) - [class `conversion_dispatch`](../explicit_conversion_dispatch.md) -- [macro `PRO_DEF_WEAK_DISPATCH`](../PRO_DEF_WEAK_DISPATCH.md) diff --git a/docs/specifications.md b/docs/specifications.md index bb7724f7..01f294dd 100644 --- a/docs/specifications.md +++ b/docs/specifications.md @@ -53,7 +53,6 @@ This document provides the API specifications for the C++ library Proxy (version | [`PRO_DEF_FREE_AS_MEM_DISPATCH` ](PRO_DEF_FREE_AS_MEM_DISPATCH.md)
*(since 3.1.0)* | Defines a dispatch type for free function call expressions with accessibility via a member function | | [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) | Defines a dispatch type for free function call expressions with accessibility | | [`PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) | Defines a dispatch type for member function call expressions with accessibility | -| [`PRO_DEF_WEAK_DISPATCH`](PRO_DEF_WEAK_DISPATCH.md)
*(deprecated since 3.2.0)* | Defines a weak dispatch type with a default implementation | ## Named Requirements diff --git a/proxy.h b/proxy.h index f3b6709c..10d8b262 100644 --- a/proxy.h +++ b/proxy.h @@ -186,16 +186,41 @@ consteval bool has_destructibility(constraint_level level) { } } -template -class destruction_guard { +template +struct proxy_helper { + static inline const auto& get_meta(const proxy& p) noexcept { + assert(p.has_value()); + return *p.meta_.operator->(); + } + static inline void reset_meta(proxy& p) noexcept { p.meta_.reset(); } + template + static add_qualifier_t get_ptr(add_qualifier_t, Q> p) { + if constexpr (std::is_same_v>) { + return std::forward>(p); + } else { + return static_cast>( + *std::launder(reinterpret_cast>(p.ptr_))); + } + } +}; + +template +class proxy_resetting_guard { public: - explicit destruction_guard(T* p) noexcept : p_(p) {} - destruction_guard(const destruction_guard&) = delete; - ~destruction_guard() noexcept(std::is_nothrow_destructible_v) - { std::destroy_at(p_); } + explicit proxy_resetting_guard(proxy& p) noexcept : p_(p) {} + proxy_resetting_guard(const proxy_resetting_guard&) = delete; + ~proxy_resetting_guard() noexcept(false) { + if constexpr (std::is_same_v>) { + p_.reset(); + } else { + std::destroy_at(std::addressof( + proxy_helper::template get_ptr(p_))); + proxy_helper::reset_meta(p_); + } + } private: - T* p_; + proxy& p_; }; template @@ -226,56 +251,56 @@ R invoke_dispatch(Args&&... args) { return D{}(std::forward(args)...); } } -template -decltype(auto) get_operand(T& ptr) { +template +decltype(auto) get_operand(P&& ptr) { if constexpr (IsDirect) { - return std::forward>(ptr); + return std::forward

(ptr); } else { - if constexpr (std::is_constructible_v) { assert(ptr); } - return *std::forward>(ptr); + if constexpr (std::is_constructible_v) { assert(ptr); } + return *std::forward

(ptr); } } -template -R conv_dispatcher(add_qualifier_t self, Args... args) +R conv_dispatcher(add_qualifier_t, Q> 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(get_operand(qp), + proxy_resetting_guard guard{self}; + return invoke_dispatch( + get_operand(proxy_helper::template get_ptr( + std::move(self))), std::forward(args)...); } else { - return invoke_dispatch(get_operand(qp), + return invoke_dispatch( + get_operand(proxy_helper::template get_ptr( + std::forward, Q>>(self))), std::forward(args)...); } } -template -R default_conv_dispatcher(add_qualifier_t, Args... args) - noexcept(invocable_dispatch) - { return invoke_dispatch(nullptr, std::forward(args)...); } template struct overload_traits : inapplicable_traits {}; template struct overload_traits_impl : applicable_traits { using return_type = R; using view_type = R(Args...) const noexcept(NE); + template using dispatcher_type = - R (*)(add_qualifier_t, Args...) noexcept(NE); + R (*)(add_qualifier_t, Q>, Args...) noexcept(NE); - template + template static consteval bool is_applicable_ptr() { if constexpr (invocable_dispatch_ptr) { return true; } else { - return invocable_dispatch; + return invocable_dispatch_ptr, Q, NE, R, Args...>; } } - template - static consteval dispatcher_type get_dispatcher() { + template + static consteval dispatcher_type get_dispatcher() { if constexpr (invocable_dispatch_ptr) { - return &conv_dispatcher; + return &conv_dispatcher; } else { - return &default_conv_dispatcher; + return &conv_dispatcher, Q, R, Args...>; } } @@ -335,21 +360,21 @@ consteval bool diagnose_proxiable_required_convention_not_implemented() { constexpr bool verdict = overload_traits>::applicable && overload_traits> - ::template is_applicable_ptr(); + ::template is_applicable_ptr(); static_assert(verdict, "not proxiable due to a required convention not implemented"); return verdict; } -template +template struct invocation_meta { constexpr invocation_meta() noexcept : dispatcher(nullptr) {} template constexpr explicit invocation_meta(std::in_place_type_t

) noexcept : dispatcher(overload_traits - ::template get_dispatcher()) {} + ::template get_dispatcher()) {} - typename overload_traits::dispatcher_type dispatcher; + typename overload_traits::template dispatcher_type dispatcher; }; template @@ -404,7 +429,7 @@ struct conv_traits_impl : inapplicable_traits {}; template requires(overload_traits>::applicable && ...) struct conv_traits_impl : applicable_traits { - using meta = composite_meta_impl>...>; template @@ -418,7 +443,7 @@ struct conv_traits_impl : applicable_traits { template static constexpr bool applicable_ptr = (overload_traits< substituted_overload_t>::template is_applicable_ptr< - C::is_direct, typename C::dispatch_type, P>() && ...); + F, C::is_direct, typename C::dispatch_type, P>() && ...); }; template struct conv_traits @@ -491,16 +516,16 @@ struct destroy_dispatch { ___PRO_STATIC_CALL(void, T& self) noexcept(std::is_nothrow_destructible_v) requires(std::is_destructible_v) { std::destroy_at(&self); } }; -template +template struct lifetime_meta_traits : std::type_identity {}; -template -struct lifetime_meta_traits - : std::type_identity> {}; -template -struct lifetime_meta_traits - : std::type_identity> {}; -template -using lifetime_meta_t = typename 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 = typename lifetime_meta_traits::type; template class ___PRO_ENFORCE_EBO composite_accessor_impl : public As... { @@ -646,7 +671,7 @@ struct facade_conv_traits_impl : applicable_traits { (conv_traits::template applicable_ptr

&& ...); template static constexpr bool is_invocable = std::is_base_of_v< - invocation_meta, conv_meta>; + invocation_meta, conv_meta>; }; template struct facade_refl_traits_impl { @@ -672,11 +697,11 @@ struct facade_traits : instantiated_t, instantiated_t { using meta = composite_meta< - lifetime_meta_t&) const noexcept, + lifetime_meta_t&) const noexcept, void(proxy&) const, F::constraints.copyability>, - lifetime_meta_t&) && noexcept, + lifetime_meta_t&) && noexcept, void(proxy&) &&, F::constraints.relocatability>, - lifetime_meta_t, typename facade_traits::conv_meta, typename facade_traits::refl_meta>; using indirect_accessor = merged_composite_accessor< @@ -739,12 +764,12 @@ struct meta_ptr_direct_impl : private M { }; template struct meta_ptr_traits_impl : std::type_identity> {}; -template +template struct meta_ptr_traits_impl< - composite_meta_impl, Ms...>> + composite_meta_impl, Ms...>> : std::type_identity, Ms...>, - invocation_meta>> {}; + invocation_meta, Ms...>, + invocation_meta>> {}; template struct meta_ptr_traits : std::type_identity> {}; template @@ -756,17 +781,6 @@ struct meta_ptr_traits : meta_ptr_traits_impl {}; template using meta_ptr = typename meta_ptr_traits::type; -template -struct meta_ptr_reset_guard { - public: - explicit meta_ptr_reset_guard(MP& meta) noexcept : meta_(meta) {} - meta_ptr_reset_guard(const meta_ptr_reset_guard&) = delete; - ~meta_ptr_reset_guard() { meta_.reset(); } - - private: - MP& meta_; -}; - template class inplace_ptr { public: @@ -791,37 +805,23 @@ class inplace_ptr { T value_; }; -template -struct proxy_helper { - static inline const auto& get_meta(const proxy& p) noexcept { - assert(p.has_value()); - return *p.meta_.operator->(); - } - template - static decltype(auto) invoke(add_qualifier_t, Q> p, Args&&... args) { - auto dispatcher = get_meta(p).template invocation_meta - ::dispatcher; - if constexpr (overload_traits::qualifier == qualifier_type::rv) { - meta_ptr_reset_guard guard{p.meta_}; - return dispatcher(std::forward>(*p.ptr_), - std::forward(args)...); - } else { - return dispatcher(std::forward>(*p.ptr_), - std::forward(args)...); - } - } - template - static add_qualifier_t, Q> access(add_qualifier_t a) { - if constexpr (std::is_base_of_v>) { - return static_cast, Q>>(a); - } else { - using IA = proxy_indirect_accessor; - return static_cast, Q>>( - *reinterpret_cast, Q>>( - static_cast>(std::addressof(a)))); - } +template +decltype(auto) invoke_impl(P&& p, Args&&... args) { + auto dispatcher = proxy_helper::get_meta(p) + .template invocation_meta::dispatcher; + return dispatcher(std::forward

(p), std::forward(args)...); +} +template +add_qualifier_t, Q> access_impl(add_qualifier_t a) { + if constexpr (std::is_base_of_v>) { + return static_cast, Q>>(a); + } else { + using IA = proxy_indirect_accessor; + return static_cast, Q>>( + *reinterpret_cast, Q>>( + static_cast>(std::addressof(a)))); } -}; +} } // namespace details @@ -836,27 +836,25 @@ struct proxy_indirect_accessor : details::facade_traits::indirect_accessor template auto proxy_invoke(proxy& p, Args&&... args) -> typename details::overload_traits::return_type { - return details::proxy_helper::template invoke(p, std::forward(args)...); + return details::invoke_impl( + p, std::forward(args)...); } template auto proxy_invoke(const proxy& p, Args&&... args) -> typename details::overload_traits::return_type { - return details::proxy_helper::template invoke(p, std::forward(args)...); + return details::invoke_impl( + p, std::forward(args)...); } template auto proxy_invoke(proxy&& p, Args&&... args) -> typename details::overload_traits::return_type { - return details::proxy_helper::template invoke< - IsDirect, D, O, details::qualifier_type::rv>( + return details::invoke_impl( std::move(p), std::forward(args)...); } template auto proxy_invoke(const proxy&& p, Args&&... args) -> typename details::overload_traits::return_type { - return details::proxy_helper::template invoke< - IsDirect, D, O, details::qualifier_type::const_rv>( + return details::invoke_impl( std::move(p), std::forward(args)...); } @@ -867,24 +865,19 @@ const R& proxy_reflect(const proxy& p) noexcept { } template -proxy& access_proxy(A& a) noexcept { - return details::proxy_helper::template access< - A, details::qualifier_type::lv>(a); -} +proxy& access_proxy(A& a) noexcept + { return details::access_impl(a); } template -const proxy& access_proxy(const A& a) noexcept { - return details::proxy_helper::template access< - A, details::qualifier_type::const_lv>(a); -} +const proxy& access_proxy(const A& a) noexcept + { return details::access_impl(a); } template proxy&& access_proxy(A&& a) noexcept { - return details::proxy_helper::template access< - A, details::qualifier_type::rv>(std::forward(a)); + return details::access_impl(std::move(a)); } template const proxy&& access_proxy(const A&& a) noexcept { - return details::proxy_helper::template access< - A, details::qualifier_type::const_rv>(std::forward(a)); + return details::access_impl( + std::move(a)); } template @@ -916,11 +909,11 @@ class proxy : public details::facade_traits::direct_accessor, requires(F::constraints.relocatability >= constraint_level::nontrivial && F::constraints.copyability != constraint_level::trivial) { if (rhs.meta_.has_value()) { - details::meta_ptr_reset_guard guard{rhs.meta_}; if constexpr (F::constraints.relocatability == constraint_level::trivial) { std::ranges::uninitialized_copy(rhs.ptr_, ptr_); meta_ = rhs.meta_; + rhs.meta_.reset(); } else { proxy_invoke( @@ -1580,18 +1573,19 @@ class bad_proxy_cast : public std::bad_cast { __SELF, ::std::forward<__Args>(__args)...); \ } \ } -#define ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) \ +#define ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME, __TTYPE) \ struct __NAME { \ - template \ + template <__TTYPE __T, class... __Args> \ ___PRO_STATIC_CALL(decltype(auto), __T&& __self, __Args&&... __args) \ ___PRO_DIRECT_FUNC_IMPL(::std::forward<__T>(__self) \ .__FUNC(::std::forward<__Args>(__args)...)) \ ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_MEM_ACCESSOR, __FNAME) \ } #define ___PRO_DEF_MEM_DISPATCH_2(__NAME, __FUNC) \ - ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FUNC) + ___PRO_DEF_MEM_DISPATCH_IMPL( \ + __NAME, __FUNC, __FUNC, ::pro::details::non_proxy_arg) #define ___PRO_DEF_MEM_DISPATCH_3(__NAME, __FUNC, __FNAME) \ - ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) + ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME, class) #define PRO_DEF_MEM_DISPATCH(__NAME, ...) \ ___PRO_EXPAND_MACRO(___PRO_DEF_MEM_DISPATCH, __NAME, __VA_ARGS__) @@ -1613,18 +1607,19 @@ ___PRO_DEBUG( \ } \ ) \ } -#define ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) \ +#define ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME, __TTYPE) \ struct __NAME { \ - template \ + template <__TTYPE __T, class... __Args> \ ___PRO_STATIC_CALL(decltype(auto), __T&& __self, __Args&&... __args) \ ___PRO_DIRECT_FUNC_IMPL(__FUNC(::std::forward<__T>(__self), \ ::std::forward<__Args>(__args)...)) \ ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_FREE_ACCESSOR, __FNAME) \ } #define ___PRO_DEF_FREE_DISPATCH_2(__NAME, __FUNC) \ - ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FUNC) + ___PRO_DEF_FREE_DISPATCH_IMPL( \ + __NAME, __FUNC, __FUNC, ::pro::details::non_proxy_arg) #define ___PRO_DEF_FREE_DISPATCH_3(__NAME, __FUNC, __FNAME) \ - ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) + ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME, class) #define PRO_DEF_FREE_DISPATCH(__NAME, ...) \ ___PRO_EXPAND_MACRO(___PRO_DEF_FREE_DISPATCH, __NAME, __VA_ARGS__) @@ -1649,6 +1644,14 @@ template using adl_accessor_arg_t = std::conditional_t, proxy_indirect_accessor>; +template struct proxy_arg_traits : inapplicable_traits {}; +template +struct proxy_arg_traits> : applicable_traits {}; +template +struct proxy_arg_traits> : applicable_traits {}; +template +concept non_proxy_arg = !proxy_arg_traits>::applicable; + #define ___PRO_DEF_CAST_ACCESSOR(Q, SELF, ...) \ template \ struct accessor<__F, __IsDirect, __D, T() Q> { \ @@ -1668,7 +1671,7 @@ struct cast_dispatch_base { #undef ___PRO_DEF_CAST_ACCESSOR struct upward_conversion_dispatch : cast_dispatch_base { - template + template ___PRO_STATIC_CALL(T&&, T&& self) noexcept { return std::forward(self); } }; @@ -1842,7 +1845,7 @@ using merge_facade_conv_t = typename add_upward_conversion_conv< F::constraints.relocatability : constraint_level::none>::type; struct proxy_view_dispatch : cast_dispatch_base { - template + template ___PRO_STATIC_CALL(auto, T& value) noexcept requires(requires { { std::addressof(*value) } noexcept; }) { return observer_ptr sign(const char (&str)[N]) -> sign; struct weak_conversion_dispatch : cast_dispatch_base { - template + template ___PRO_STATIC_CALL(auto, const P& self) noexcept requires( requires(const typename P::weak_type& w) @@ -2064,7 +2067,7 @@ struct proxy_cast_accessor_impl { : proxy_cast_accessor_impl {} struct proxy_cast_dispatch { - template + template ___PRO_STATIC_CALL(void, T&& self, proxy_cast_context ctx) { if (typeid(T) == *ctx.type_ptr) { if (ctx.is_ref) { @@ -2250,18 +2253,18 @@ struct operator_dispatch; #define ___PRO_DEF_LHS_BINARY_OP_ACCESSOR ___PRO_DEF_LHS_ANY_OP_ACCESSOR #define ___PRO_DEF_LHS_ALL_OP_ACCESSOR ___PRO_DEF_LHS_ANY_OP_ACCESSOR #define ___PRO_LHS_LEFT_OP_DISPATCH_BODY_IMPL(...) \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self) \ ___PRO_DIRECT_FUNC_IMPL(__VA_ARGS__ std::forward(self)) #define ___PRO_LHS_UNARY_OP_DISPATCH_BODY_IMPL(...) \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self) \ ___PRO_DIRECT_FUNC_IMPL(__VA_ARGS__ std::forward(self)) \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self, int) \ ___PRO_DIRECT_FUNC_IMPL(std::forward(self) __VA_ARGS__) #define ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL(...) \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL( \ std::forward(self) __VA_ARGS__ std::forward(arg)) @@ -2296,7 +2299,7 @@ ___PRO_DEBUG( \ #define ___PRO_RHS_OP_DISPATCH_IMPL(...) \ template <> \ struct operator_dispatch<#__VA_ARGS__, true> { \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL( \ std::forward(arg) __VA_ARGS__ std::forward(self)) \ @@ -2343,7 +2346,7 @@ ___PRO_DEBUG( \ #define ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(...) \ template <> \ struct operator_dispatch<#__VA_ARGS__, false> { \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL(std::forward(self) __VA_ARGS__ \ std::forward(arg)) \ @@ -2352,7 +2355,7 @@ ___PRO_DEBUG( \ }; \ template <> \ struct operator_dispatch<#__VA_ARGS__, true> { \ - template \ + template \ ___PRO_STATIC_CALL(decltype(auto), T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL( \ std::forward(arg) __VA_ARGS__ std::forward(self)) \ @@ -2397,7 +2400,7 @@ ___PRO_BINARY_OP_DISPATCH_IMPL(->*) template <> struct operator_dispatch<"()", false> { - template + template ___PRO_STATIC_CALL(decltype(auto), T&& self, Args&&... args) ___PRO_DIRECT_FUNC_IMPL( std::forward(self)(std::forward(args)...)) @@ -2406,12 +2409,12 @@ struct operator_dispatch<"()", false> { template <> struct operator_dispatch<"[]", false> { #if __cpp_multidimensional_subscript >= 202110L - template + template ___PRO_STATIC_CALL(decltype(auto), T&& self, Args&&... args) ___PRO_DIRECT_FUNC_IMPL( std::forward(self)[std::forward(args)...]) #else - template + template ___PRO_STATIC_CALL(decltype(auto), T&& self, Arg&& arg) ___PRO_DIRECT_FUNC_IMPL(std::forward(self)[std::forward(arg)]) #endif // __cpp_multidimensional_subscript >= 202110L @@ -2438,11 +2441,11 @@ struct operator_dispatch<"[]", false> { struct implicit_conversion_dispatch : details::cast_dispatch_base { - template + template ___PRO_STATIC_CALL(T&&, T&& self) noexcept { return std::forward(self); } }; struct explicit_conversion_dispatch : details::cast_dispatch_base { - template + template ___PRO_STATIC_CALL(auto, T&& self) noexcept { return details::explicit_conversion_adapter{std::forward(self)}; } }; @@ -2457,19 +2460,10 @@ template struct weak_dispatch : D { using D::operator(); template - [[noreturn]] ___PRO_STATIC_CALL(details::wildcard, std::nullptr_t, Args&&...) + [[noreturn]] ___PRO_STATIC_CALL(details::wildcard, Args&&...) { ___PRO_THROW(not_implemented{}); } }; -#define PRO_DEF_WEAK_DISPATCH(__NAME, __D, __FUNC) \ - struct [[deprecated("'PRO_DEF_WEAK_DISPATCH' is deprecated. " \ - "Use pro::weak_dispatch<" #__D "> instead.")]] __NAME : __D { \ - using __D::operator(); \ - template \ - ___PRO_STATIC_CALL(decltype(auto), ::std::nullptr_t, __Args&&... __args) \ - ___PRO_DIRECT_FUNC_IMPL(__FUNC(::std::forward<__Args>(__args)...)) \ - } - } // namespace pro #if __STDC_HOSTED__ diff --git a/samples/PRO_DEF_WEAK_DISPATCH.cpp b/samples/PRO_DEF_WEAK_DISPATCH.cpp deleted file mode 100644 index 2ea7fb48..00000000 --- a/samples/PRO_DEF_WEAK_DISPATCH.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -// This file contains example code from PRO_DEF_WEAK_DISPATCH.md. - -#include -#include -#include - -#include "proxy.h" - -struct NotImplemented { - explicit NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; } - - template - operator T() const noexcept { std::terminate(); } // Or std::unreachable() in C++23 -}; - -PRO_DEF_MEM_DISPATCH(MemAt, at); -PRO_DEF_WEAK_DISPATCH(WeakMemAt, MemAt, NotImplemented); - -struct WeakDictionary : pro::facade_builder - ::add_convention - ::build {}; - -int main() { - std::vector v{"hello", "world"}; - pro::proxy p1 = &v; - std::cout << p1->at(1) << "\n"; // Prints "world" - pro::proxy p2 = pro::make_proxy(123); - try { - p2->at(1); - } catch (const std::runtime_error& e) { - std::cout << e.what() << "\n"; // Prints "Not implemented!" - } -} diff --git a/tests/freestanding/proxy_freestanding_tests.cpp b/tests/freestanding/proxy_freestanding_tests.cpp index fc584e55..6eb1c172 100644 --- a/tests/freestanding/proxy_freestanding_tests.cpp +++ b/tests/freestanding/proxy_freestanding_tests.cpp @@ -5,18 +5,20 @@ #include "proxy.h" constexpr unsigned DefaultHash = -1; -unsigned GetHash(int v) { return static_cast(v + 3) * 31; } -unsigned GetHash(double v) { return static_cast(v * v + 5) * 87; } -unsigned GetHash(const char* v) { +unsigned GetHashImpl(int v) { return static_cast(v + 3) * 31; } +unsigned GetHashImpl(double v) { return static_cast(v * v + 5) * 87; } +unsigned GetHashImpl(const char* v) { unsigned result = 91u; for (int i = 0; v[i]; ++i) { result = result * 47u + v[i]; } return result; } -unsigned GetHash(std::nullptr_t) { return DefaultHash; } +template +unsigned GetHashImpl(const pro::proxy_indirect_accessor&) + { return DefaultHash; } +PRO_DEF_FREE_DISPATCH(FreeGetHash, GetHashImpl, GetHash); -PRO_DEF_FREE_DISPATCH(FreeGetHash, GetHash); struct Hashable : pro::facade_builder ::add_convention ::build {}; @@ -28,15 +30,15 @@ extern "C" int main() { std::tuple t{11, 22}; pro::proxy p; p = &i; - if (GetHash(*p) != GetHash(i)) { + if (GetHash(*p) != GetHashImpl(i)) { return 1; } p = &d; - if (GetHash(*p) != GetHash(d)) { + if (GetHash(*p) != GetHashImpl(d)) { return 1; } p = pro::make_proxy_inplace(s); - if (GetHash(*p) != GetHash(s)) { + if (GetHash(*p) != GetHashImpl(s)) { return 1; } p = &t; diff --git a/tests/proxy_invocation_tests.cpp b/tests/proxy_invocation_tests.cpp index 3610138e..f2506eb9 100644 --- a/tests/proxy_invocation_tests.cpp +++ b/tests/proxy_invocation_tests.cpp @@ -100,7 +100,9 @@ struct Weak : pro::facade_builder template pro::proxy> GetWeakImpl(const std::shared_ptr& p) { return pro::make_proxy, std::weak_ptr>(p); } template -pro::proxy> GetWeakImpl(std::nullptr_t) { return nullptr; } +pro::proxy> GetWeakImpl(const pro::proxy&) { return nullptr; } +template +void GetWeakImpl(T&&) = delete; template PRO_DEF_FREE_DISPATCH(FreeGetWeak, GetWeakImpl, GetWeak);