Skip to content

Commit

Permalink
Simplify proxy_invoke and proxy_reflect (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
mingxwa authored Jan 2, 2025
1 parent 1f2037f commit 62c052e
Show file tree
Hide file tree
Showing 21 changed files with 283 additions and 268 deletions.
2 changes: 1 addition & 1 deletion docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<F, C, Os...>` are named `accessibility_func_name`. Effectively equivalent to:
`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via member function overloads named `accessibility_func_name`. Effectively equivalent to:

```cpp
struct dispatch_name {
Expand Down
17 changes: 9 additions & 8 deletions docs/PRO_DEF_FREE_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`. Let `accessor_arg` be `std::conditional_t<C::is_direct, proxy<F>, proxy_indirect_accessor<F>>`. The functions provided by `typename dispatch_name::template accessor<F, C, Os...>` 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:
`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via free function overloads named `accessibility_func_name`. Effectively equivalent to:

```cpp
struct dispatch_name {
Expand All @@ -27,16 +27,17 @@ struct dispatch_name {
return func_name(std::forward<T>(self), std::forward<Args>(args)...);
}

template <class F, class C, class... Os> struct accessor {
template <class F, bool IsDirect, class D, class... Os>
struct accessor {
accessor() = delete;
};
template <class F, class C, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
struct accessor<F, C, Os...> : accessor<F, C, Os>... {};
template <class F, class C, class R, class... Args>
struct accessor<F, C, R(Args...) cv ref noex> {
template <class F, bool IsDirect, class D, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {};
template <class F, bool IsDirect, class D, class R, class... Args>
struct accessor<F, IsDirect, D, R(Args...) cv ref noex> {
friend R accessibility_func_name(accessor_arg cv ref self, Args... args) noex {
return pro::proxy_invoke<C, R(Args...) cv ref noex>(pro::access_proxy<F>(std::forward<accessor_arg cv ref>(self)), std::forward<Args>(args)...);
return pro::proxy_invoke<IsDirect, D, R(Args...) cv ref noex>(pro::access_proxy<F>(std::forward<accessor_arg cv ref>(self)), std::forward<Args>(args)...);
}
};
}
Expand Down
18 changes: 9 additions & 9 deletions docs/PRO_DEF_MEM_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<F, C, Os...>` are named `accessibility_func_name`. Effectively equivalent to:
`(2)` Defines a class named `dispatch_name` of member function call expressions of `func_name` with accessibility via member function overloads named `accessibility_func_name`. Effectively equivalent to:

```cpp
struct dispatch_name {
Expand All @@ -27,19 +27,19 @@ struct dispatch_name {
return std::forward<T>(self).func_name(std::forward<Args>(args)...);
}

template <class F, class C, class... Os>
template <class F, bool IsDirect, class D, class... Os>
struct accessor {
accessor() = delete;
};
template <class F, class C, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
struct accessor<F, C, Os...> : accessor<F, C, Os>... {
using accessor<F, C, Os>::accessibility_func_name ...;
template <class F, bool IsDirect, class D, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {
using accessor<F, IsDirect, D, Os>::accessibility_func_name ...;
};
template <class F, class C, class R, class... Args>
struct accessor<F, C, R(Args...) cv ref noex> {
template <class F, bool IsDirect, class D, class R, class... Args>
struct accessor<F, IsDirect, D, R(Args...) cv ref noex> {
R accessibility_func_name(Args... args) cv ref noex {
return pro::proxy_invoke<C, R(Args...) cv ref noex>(pro::access_proxy<F>(std::forward<accessor cv ref>(*this)), std::forward<Args>(args)...);
return pro::proxy_invoke<IsDirect, D, R(Args...) cv ref noex>(pro::access_proxy<F>(std::forward<accessor cv ref>(*this)), std::forward<Args>(args)...);
}
};
}
Expand Down
8 changes: 4 additions & 4 deletions docs/ProAccessible.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Named requirements: *ProAccessible*

Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), a type `T` meets the *ProAccessible* requirements of types `F, Args...`, if the following expressions are well-formed and have the specified semantics.
Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), a type `T` meets the *ProAccessible* requirements of type `F`, if the following expressions are well-formed and have the specified semantics.

| Expressions | Semantics |
| ------------------------------------------- | ------------------------------------------------------------ |
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a *nothrow-default-constructible*, *trivially-copyable* type, and shall not be [final](https://en.cppreference.com/w/cpp/language/final). |
| Expressions | Semantics |
| ---------------------------------- | ------------------------------------------------------------ |
| `typename T::template accessor<F>` | A type that provides accessibility to `proxy`. It shall be a *nothrow-default-constructible*, *trivially-copyable* type, and shall not be [final](https://en.cppreference.com/w/cpp/language/final). |

## See Also

Expand Down
5 changes: 2 additions & 3 deletions docs/access_proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ int main() {
std::cout << ToString(*p) << "\n"; // Prints: "123"
// How it works behind the scenes
using Convention = std::tuple_element_t<0u, Stringable::convention_types>;
using Accessor = Convention::accessor<Stringable>;
using Accessor = FreeToString::accessor<Stringable, false, FreeToString, std::string()>;
static_assert(std::is_base_of_v<Accessor, std::remove_reference_t<decltype(*p)>>);
Accessor& a = static_cast<Accessor&>(*p);
pro::proxy<Stringable>& p2 = pro::access_proxy<Stringable>(a);
std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints: "true" because access_proxy converts
// an accessor back to the original proxy
auto result = pro::proxy_invoke<Convention, std::string()>(p2);
auto result = pro::proxy_invoke<false, FreeToString, std::string()>(p2);
std::cout << result << "\n"; // Prints: "123"
}
```
Expand Down
4 changes: 2 additions & 2 deletions docs/basic_facade_builder/add_convention.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ The alias templates `add_convention`, `add_indirect_convention`, and `add_direct
- `IC::is_direct` is `false`.
- `typename IC::dispatch_type` is `D`.
- `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`.
- `typename IC::template accessor<F>` is `typename D::template accessor<F, IC, Os...>` if applicable.
- `typename IC::template accessor<F>` is `typename D::template accessor<F, false, D, Os...>` if applicable.
- `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs`, where:
- `IC::is_direct` is `true`.
- `typename IC::dispatch_type` is `D`.
- `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`.
- `typename IC::template accessor<F>` is `typename D::template accessor<F, IC, Os...>` if applicable.
- `typename IC::template accessor<F>` is `typename D::template accessor<F, true, D, Os...>` if applicable.
When `Cs` already contains a convention type `IC2` where `IC2::is_direct == IC::is_direct && std::is_same_v<typename IC2::dispatch_type, typename IC::dispatch_type>` is `true`, `Os` merges with `typename IC2::overload_types` and removes duplicates, and `std::tuple_size_v<Cs>` shall not change.
Expand Down
22 changes: 11 additions & 11 deletions docs/basic_facade_builder/add_reflection.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ using add_direct_reflection = basic_facade_builder</* see below */>;
The alias templates `add_reflection`, `add_indirect_reflection` and `add_direct_reflection` of `basic_facade_builder<Cs, Rs, C>` add reflection types to the template parameters. Specifically,

- `add_reflection` is equivalent to `add_indirect_reflection`.
- `add_indirect_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where:
- `R2::is_direct` is `false`.
- `typename R2::reflector_type` is `R`.
- `typename R2::template accessor<F>` is `typename R2::template accessor<F, R2>` if applicable.
- `add_direct_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where:
- `R2::is_direct` is `true`.
- `typename R2::reflector_type` is `R`.
- `typename R2::template accessor<F>` is `typename R2::template accessor<F, R2>` if applicable.
- `add_indirect_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where:
- `Refl::is_direct` is `false`.
- `typename Refl::reflector_type` is `R`.
- `typename Refl::template accessor<F>` is `typename R::template accessor<F, false, R>` if applicable.
- `add_direct_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where:
- `Refl::is_direct` is `true`.
- `typename Refl::reflector_type` is `R`.
- `typename Refl::template accessor<F>` is `typename R::template accessor<F, true, R>` if applicable.

When `Rs` already contains `R2`, the template parameters shall not change.
When `Rs` already contains `Refl`, the template parameters shall not change.

## Notes

Expand All @@ -42,10 +42,10 @@ class RttiReflector {
template <class T>
constexpr explicit RttiReflector(std::in_place_type_t<T>) : type_(typeid(T)) {}

template <class F, class R>
template <class F, bool IsDirect, class R>
struct accessor {
const char* GetTypeName() const noexcept {
const RttiReflector& self = pro::proxy_reflect<R>(pro::access_proxy<F>(*this));
const RttiReflector& self = pro::proxy_reflect<IsDirect, R>(pro::access_proxy<F>(*this));
return self.type_.name();
}
};
Expand Down
18 changes: 9 additions & 9 deletions docs/explicit_conversion_dispatch/accessor.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

```cpp
// (1)
template <class F, class C, class... Os>
template <class F, bool IsDirect, class D, class... Os>
struct accessor {
accessor() = delete;
};

// (2)
template <class F, class C, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
struct accessor<F, C, Os...> : accessor<F, C, Os>... {
using accessor<F, C, Os>::operator return-type-of<Os>...;
template <class F, bool IsDirect, class D, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {
using accessor<F, IsDirect, D, Os>::operator return-type-of<Os>...;
};

// (3)
template <class F, class C>
struct accessor<F, C, T() cv ref noex> {
template <class F, bool IsDirect, class D>
struct accessor<F, IsDirect, D, T() cv ref noex> {
explicit operator T() cv ref noex;
};
```
`(1)` The default implementation of `accessor` is not constructible.
`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor<F, C, Os>...` are default-constructible, inherits all `accessor<F, C, Os>...` types and `using` their `operator return-type-of<Os>`. `return-type-of<O>` denotes the *return type* of the overload type `O`.
`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor<F, IsDirect, D, Os>...` are default-constructible, inherits all `accessor<F, IsDirect, D, Os>...` types and `using` their `operator return-type-of<Os>`. `return-type-of<O>` 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<C, T() cv ref noex>(access_proxy<F>(std::forward<accessor cv ref>(*this)))`.
`(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<IsDirect, D, T() cv ref noex>(access_proxy<F>(std::forward<accessor cv ref>(*this)))`.
18 changes: 9 additions & 9 deletions docs/implicit_conversion_dispatch/accessor.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

```cpp
// (1)
template <class F, class C, class... Os>
template <class F, bool IsDirect, class D, class... Os>
struct accessor {
accessor() = delete;
};

// (2)
template <class F, class C, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
struct accessor<F, C, Os...> : accessor<F, C, Os>... {
using accessor<F, C, Os>::operator return-type-of<Os>...;
template <class F, bool IsDirect, class D, class... Os>
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {
using accessor<F, IsDirect, D, Os>::operator return-type-of<Os>...;
};

// (3)
template <class F, class C>
struct accessor<F, C, T() cv ref noex> {
template <class F, bool IsDirect, class D>
struct accessor<F, IsDirect, D, T() cv ref noex> {
operator T() cv ref noex;
};
```
`(1)` The default implementation of `accessor` is not constructible.
`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor<F, C, Os>...` are default-constructible, inherits all `accessor<F, C, Os>...` types and `using` their `operator return-type-of<Os>`. `return-type-of<O>` denotes the *return type* of the overload type `O`.
`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor<F, IsDirect, D, Os>...` are default-constructible, inherits all `accessor<F, IsDirect, D, Os>...` types and `using` their `operator return-type-of<Os>`. `return-type-of<O>` 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<C, T() cv ref noex>(access_proxy<F>(std::forward<accessor cv ref>(*this)))`.
`(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<IsDirect, D, T() cv ref noex>(access_proxy<F>(std::forward<accessor cv ref>(*this)))`.
Loading

0 comments on commit 62c052e

Please sign in to comment.