From 64620549cb0ed08b178e2acb4cb05866eddd3a15 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Sun, 15 Dec 2024 10:48:23 +0800 Subject: [PATCH 1/2] Fix ADL --- docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md | 4 +- docs/PRO_DEF_FREE_DISPATCH.md | 6 +- docs/PRO_DEF_MEM_DISPATCH.md | 4 +- docs/explicit_conversion_dispatch/accessor.md | 4 +- docs/implicit_conversion_dispatch/accessor.md | 4 +- docs/operator_dispatch/accessor.md | 18 +- docs/proxy.md | 2 +- docs/proxy_indirect_accessor.md | 18 ++ docs/specifications.md | 1 + proxy.h | 233 ++++++++++-------- tests/proxy_invocation_tests.cpp | 27 +- 11 files changed, 188 insertions(+), 133 deletions(-) create mode 100644 docs/proxy_indirect_accessor.md diff --git a/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md b/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md index cb2e1d2..55f41eb 100644 --- a/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md +++ b/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md @@ -16,7 +16,7 @@ PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); `(1)` Equivalent to `PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, func_name);` -`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via a member function. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name`. Let `SELF` be `std::forward(*this)`, effectively equivalent to: +`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via a member function. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name`. Effectively equivalent to: ```cpp struct dispatch_name { @@ -39,7 +39,7 @@ struct dispatch_name { template struct accessor { R accessibility_func_name(Args... args) cv ref noex { - return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); + return pro::proxy_invoke(pro::access_proxy(std::forward(*this)), std::forward(args)...); } }; } diff --git a/docs/PRO_DEF_FREE_DISPATCH.md b/docs/PRO_DEF_FREE_DISPATCH.md index 07557ce..67e5e71 100644 --- a/docs/PRO_DEF_FREE_DISPATCH.md +++ b/docs/PRO_DEF_FREE_DISPATCH.md @@ -16,7 +16,7 @@ PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, accessibility_func_name); `(1)` Equivalent to `PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, func_name);` -`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name` and can be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `accessor` is an associated class of the arguments. Let `SELF` be `std::forward(self)`, effectively equivalent to: +`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. Let `accessor_arg` be `std::conditional_t, proxy_indirect_accessor>`. The functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name` and can be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `accessor_arg` is an associated class of the arguments. Effectively equivalent to: ```cpp struct dispatch_name { @@ -35,8 +35,8 @@ struct dispatch_name { struct accessor : accessor... {}; template struct accessor { - friend R accessibility_func_name(accessor cv ref self, Args... args) noex { - return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); + friend R accessibility_func_name(accessor_arg cv ref self, Args... args) noex { + return pro::proxy_invoke(pro::access_proxy(std::forward(self)), std::forward(args)...); } }; } diff --git a/docs/PRO_DEF_MEM_DISPATCH.md b/docs/PRO_DEF_MEM_DISPATCH.md index 8932d7b..f012aa5 100644 --- a/docs/PRO_DEF_MEM_DISPATCH.md +++ b/docs/PRO_DEF_MEM_DISPATCH.md @@ -16,7 +16,7 @@ PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); `(1)` Equivalent to `PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, func_name);` -`(2)` Defines a class named `dispatch_name` of member function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv, ref, noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name`. Let `SELF` be `std::forward(*this)`, effectively equivalent to: +`(2)` Defines a class named `dispatch_name` of member function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv, ref, noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name`. Effectively equivalent to: ```cpp struct dispatch_name { @@ -39,7 +39,7 @@ struct dispatch_name { template struct accessor { R accessibility_func_name(Args... args) cv ref noex { - return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); + return pro::proxy_invoke(pro::access_proxy(std::forward(*this)), std::forward(args)...); } }; } diff --git a/docs/explicit_conversion_dispatch/accessor.md b/docs/explicit_conversion_dispatch/accessor.md index a81237d..8d6716c 100644 --- a/docs/explicit_conversion_dispatch/accessor.md +++ b/docs/explicit_conversion_dispatch/accessor.md @@ -21,10 +21,8 @@ struct accessor { }; ``` -Let `SELF` be `std::forward(*this)`. - `(1)` The default implementation of `accessor` is not constructible. `(2)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible, inherits all `accessor...` types and `using` their `operator return-type-of`. `return-type-of` denotes the *return type* of the overload type `O`. -`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an explicit `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke(access_proxy(SELF))`. +`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an explicit `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke(access_proxy(std::forward(*this)))`. diff --git a/docs/implicit_conversion_dispatch/accessor.md b/docs/implicit_conversion_dispatch/accessor.md index fa2ead8..0b78300 100644 --- a/docs/implicit_conversion_dispatch/accessor.md +++ b/docs/implicit_conversion_dispatch/accessor.md @@ -21,10 +21,8 @@ struct accessor { }; ``` -Let `SELF` be `std::forward(*this)`. - `(1)` The default implementation of `accessor` is not constructible. `(2)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible, inherits all `accessor...` types and `using` their `operator return-type-of`. `return-type-of` denotes the *return type* of the overload type `O`. -`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an implicit `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke(access_proxy(SELF))`. +`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an implicit `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke(access_proxy(std::forward(*this)))`. diff --git a/docs/operator_dispatch/accessor.md b/docs/operator_dispatch/accessor.md index 513f568..69f1e54 100644 --- a/docs/operator_dispatch/accessor.md +++ b/docs/operator_dispatch/accessor.md @@ -25,7 +25,7 @@ struct accessor : accessor... { `(2)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible types, inherits all `accessor...` types and `using` their `operator sop`. -When `Rhs` is `false`, the other specializations are defined as follows, where `sizeof...(Os)` is `1` and the only type `O` qualified with `cv ref noex` (let `SELF` be `std::forward(*this)`): +When `Rhs` is `false`, the other specializations are defined as follows, where `sizeof...(Os)` is `1` and the only type `O` qualified with `cv ref noex` (let `ACCESS_PROXY_EXPR` be `access_proxy(std::forward(*this))`): ### Regular SOPs @@ -39,7 +39,7 @@ struct accessor { } ``` -`(3)` Provides an `operator sop(Args...)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Args...)` is equivalent to `return proxy_invoke(access_proxy(SELF), std::forward(args)...)`. +`(3)` Provides an `operator sop(Args...)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Args...)` is equivalent to `return proxy_invoke(ACCESS_PROXY_EXPR, std::forward(args)...)`. ### `!` and `~` @@ -53,7 +53,7 @@ struct accessor { } ``` -`(4)` Provides an `operator sop()` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop()` is equivalent to `return proxy_invoke(access_proxy(SELF))`. +`(4)` Provides an `operator sop()` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop()` is equivalent to `return proxy_invoke(ACCESS_PROXY_EXPR)`. ### Assignment SOPs @@ -67,7 +67,7 @@ struct accessor { } ``` -`(4)` Provides an `operator sop(Arg)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Arg)` calls `proxy_invoke(access_proxy(SELF), std::forward(arg))` and returns `access_proxy(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy(SELF)` when `C::is_direct` is `false`. +`(4)` Provides an `operator sop(Arg)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Arg)` calls `proxy_invoke(ACCESS_PROXY_EXPR, std::forward(arg))` and returns `ACCESS_PROXY_EXPR` when `C::is_direct` is `true`, or otherwise, returns `*ACCESS_PROXY_EXPR` when `C::is_direct` is `false`. ## Right-Hand-Side Operand Specializations @@ -80,7 +80,7 @@ struct accessor : accessor... {}; `(6)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible types, inherits all `accessor...` types. -When `Rhs` is `true`, the other specializations are defined as follows, where `sizeof...(Os)` is `1` and the only type `O` qualified with `cv ref noex` (let `SELF` be `std::forward(self)`): +When `Rhs` is `true`, the other specializations are defined as follows, where `sizeof...(Os)` is `1` and the only type `O` qualified with `cv ref noex` (let `accessor_arg` be `std::conditional_t, proxy_indirect_accessor>`, `ACCESS_PROXY_EXPR` be `access_proxy(std::forward(self))`): ### Regular SOPs @@ -90,11 +90,11 @@ When `Sign` is one of `"+"`, `"-"`, `"*"`, `"/"`, `"%"`, `"=="`, `"!="`, `">"`, // (7) template struct accessor { - friend R operator sop (Arg arg, accessor cv ref self) noex; + friend R operator sop (Arg arg, accessor_arg cv ref self) noex; } ``` -`(7)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` is equivalent to `return proxy_invoke(access_proxy(SELF), std::forward(arg))`. +`(7)` Provides a `friend operator sop(Arg arg, accessor_arg cv ref self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor_arg cv ref self)` is equivalent to `return proxy_invoke(ACCESS_PROXY_EXPR, std::forward(arg))`. ### Assignment SOPs @@ -104,8 +104,8 @@ When `Sign` is one of `"+="`, `"-="`, `"*="`, `"/="`, `"&="`, `"|="`, `"^="`, `" // (8) template struct accessor { - friend /* see below */ operator sop (Arg arg, accessor cv ref self) noex; + friend /* see below */ operator sop (Arg arg, accessor_arg cv ref self) noex; } ``` -`(8)` Provides a `friend operator sop(Arg arg, accessor cv ref)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor cv ref)` calls `proxy_invoke(access_proxy(SELF), std::forward(arg))` and returns `access_proxy(SELF)` when `C::is_direct` is `true`, or otherwise, returns `*access_proxy(SELF)` when `C::is_direct` is `false`. +`(8)` Provides a `friend operator sop(Arg arg, accessor_arg cv ref self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, accessor_arg cv ref self)` calls `proxy_invoke(ACCESS_PROXY_EXPR, std::forward(arg))` and returns `ACCESS_PROXY_EXPR` when `C::is_direct` is `true`, or otherwise, returns `*ACCESS_PROXY_EXPR` when `C::is_direct` is `false`. diff --git a/docs/proxy.md b/docs/proxy.md index 5fd85c7..04c3578 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -7,7 +7,7 @@ class proxy; Class template `proxy` is a general-purpose polymorphic wrapper for C++ objects. Unlike other polymorphic wrappers in the C++ standard (e.g., [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function), [`std::move_only_function`](https://en.cppreference.com/w/cpp/utility/functional/move_only_function), [`std::any`](https://en.cppreference.com/w/cpp/utility/any), etc.), `proxy` is based on pointer semantics. It supports flexible lifetime management without runtime [garbage collection (GC)](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) at runtime, and offers best-in-class code generation quality, extendibility and accessibility. -To instantiate `proxy`, `F` shall model [concept `facade`](facade.md). As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Cs`, and `typename F::reflection_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Rs`. For each type `T` in `Cs` or `Rs`, if `T` meets the [*ProAccessible* requirements](ProAccessible.md) of `F`, `typename T::template accessor` is inherited by `proxy` when `T::is_direct` is `true`. Otherwise, it is inherited by the return type of [`operator*`](proxy/indirection.md) when `T::is_direct` is `false`. Implementation of accessors can call [`access_proxy`](access_proxy.md) to access the `proxy` object. It is recommended to use [`facade_builder`](basic_facade_builder.md) to define a facade type. +To instantiate `proxy`, `F` shall model [concept `facade`](facade.md). As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Cs`, and `typename F::reflection_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Rs`. For each type `T` in `Cs` or `Rs`, if `T` meets the [*ProAccessible* requirements](ProAccessible.md) of `F`, `typename T::template accessor` is inherited by `proxy` when `T::is_direct` is `true`. Otherwise, it is inherited by [`proxy_indirect_accessor`](proxy_indirect_accessor.md), the return type of [`operator*`](proxy/indirection.md), when `T::is_direct` is `false`. Implementation of accessors can call [`access_proxy`](access_proxy.md) to access the `proxy` object. It is recommended to use [`facade_builder`](basic_facade_builder.md) to define a facade type. Any instance of `proxy` at any given point in time either *contains a value* or *does not contain a value*. If a `proxy` *contains a value*, the type of the value shall be a pointer type `P` where [`proxiable`](proxiable.md) is `true`, and the value is guaranteed to be allocated as part of the `proxy` object footprint, i.e. no dynamic memory allocation occurs. However, `P` may allocate during its construction, depending on its implementation. diff --git a/docs/proxy_indirect_accessor.md b/docs/proxy_indirect_accessor.md new file mode 100644 index 0000000..6061002 --- /dev/null +++ b/docs/proxy_indirect_accessor.md @@ -0,0 +1,18 @@ +# Class template `proxy_indirect_accessor` + +```cpp +template +class proxy_indirect_accessor; +``` + +Class template `proxy_indirect_accessor` provides indirection accessibility for `proxy`. To instantiate `proxy_indirect_accessor`, `F` shall model [concept `facade`](facade.md). As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Cs`, and `typename F::reflection_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Rs`. For each type `T` in `Cs` or `Rs`, if `T` meets the [*ProAccessible* requirements](ProAccessible.md) of `F` and `T::is_direct` is `false`, `typename T::template accessor` is inherited by `proxy_indirect_accessor`. + +## Member functions + +| Name | Description | +| ----------------------- | ----------------------------------------- | +| (constructor) [deleted] | Has neither default nor copy constructors | + +## See also + +[function template `access_proxy`](access_proxy.md) diff --git a/docs/specifications.md b/docs/specifications.md index f997d88..870f8b6 100644 --- a/docs/specifications.md +++ b/docs/specifications.md @@ -21,6 +21,7 @@ This document provides the API specifications for the C++ library Proxy (version | [`operator_dispatch`](operator_dispatch.md) | Dispatch type for operator expressions with accessibility | | [`explicit_conversion_dispatch`
`conversion_dispatch`](explicit_conversion_dispatch.md) | Dispatch type for explicit conversion expressions with accessibility | | [`implicit_conversion_dispatch`](implicit_conversion_dispatch.md) | Dispatch type for implicit conversion expressions with accessibility | +| [`proxy_indirect_accessor`](proxy_indirect_accessor.md) | Provides indirection accessibility for `proxy` types | ## Functions diff --git a/proxy.h b/proxy.h index 9186c69..e3d37a4 100644 --- a/proxy.h +++ b/proxy.h @@ -49,6 +49,7 @@ struct proxiable_ptr_constraints { constraint_level destructibility; }; +template struct proxy_indirect_accessor; template class proxy; namespace details { @@ -457,11 +458,10 @@ struct lifetime_meta_traits template