Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify proxy_invoke and proxy_reflect #226

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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