Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit 62c052e

Browse files
authored
Simplify proxy_invoke and proxy_reflect (#226)
1 parent 1f2037f commit 62c052e

21 files changed

Lines changed: 283 additions & 268 deletions

docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name);
1616

1717
`(1)` Equivalent to `PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, func_name);`
1818

19-
`(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:
19+
`(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:
2020

2121
```cpp
2222
struct dispatch_name {

docs/PRO_DEF_FREE_DISPATCH.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, accessibility_func_name);
1616

1717
`(1)` Equivalent to `PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, func_name);`
1818

19-
`(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:
19+
`(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:
2020

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

30-
template <class F, class C, class... Os> struct accessor {
30+
template <class F, bool IsDirect, class D, class... Os>
31+
struct accessor {
3132
accessor() = delete;
3233
};
33-
template <class F, class C, class... Os>
34-
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
35-
struct accessor<F, C, Os...> : accessor<F, C, Os>... {};
36-
template <class F, class C, class R, class... Args>
37-
struct accessor<F, C, R(Args...) cv ref noex> {
34+
template <class F, bool IsDirect, class D, class... Os>
35+
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
36+
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {};
37+
template <class F, bool IsDirect, class D, class R, class... Args>
38+
struct accessor<F, IsDirect, D, R(Args...) cv ref noex> {
3839
friend R accessibility_func_name(accessor_arg cv ref self, Args... args) noex {
39-
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)...);
40+
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)...);
4041
}
4142
};
4243
}

docs/PRO_DEF_MEM_DISPATCH.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name);
1616

1717
`(1)` Equivalent to `PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, func_name);`
1818

19-
`(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:
19+
`(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:
2020

2121
```cpp
2222
struct dispatch_name {
@@ -27,19 +27,19 @@ struct dispatch_name {
2727
return std::forward<T>(self).func_name(std::forward<Args>(args)...);
2828
}
2929

30-
template <class F, class C, class... Os>
30+
template <class F, bool IsDirect, class D, class... Os>
3131
struct accessor {
3232
accessor() = delete;
3333
};
34-
template <class F, class C, class... Os>
35-
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, C, Os>> && ...))
36-
struct accessor<F, C, Os...> : accessor<F, C, Os>... {
37-
using accessor<F, C, Os>::accessibility_func_name ...;
34+
template <class F, bool IsDirect, class D, class... Os>
35+
requires(sizeof...(Os) > 1u && (std::is_constructible_v<accessor<F, IsDirect, D, Os>> && ...))
36+
struct accessor<F, IsDirect, D, Os...> : accessor<F, IsDirect, D, Os>... {
37+
using accessor<F, IsDirect, D, Os>::accessibility_func_name ...;
3838
};
39-
template <class F, class C, class R, class... Args>
40-
struct accessor<F, C, R(Args...) cv ref noex> {
39+
template <class F, bool IsDirect, class D, class R, class... Args>
40+
struct accessor<F, IsDirect, D, R(Args...) cv ref noex> {
4141
R accessibility_func_name(Args... args) cv ref noex {
42-
return pro::proxy_invoke<C, R(Args...) cv ref noex>(pro::access_proxy<F>(std::forward<accessor cv ref>(*this)), std::forward<Args>(args)...);
42+
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)...);
4343
}
4444
};
4545
}

docs/ProAccessible.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Named requirements: *ProAccessible*
22

3-
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.
3+
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.
44

5-
| Expressions | Semantics |
6-
| ------------------------------------------- | ------------------------------------------------------------ |
7-
| `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). |
5+
| Expressions | Semantics |
6+
| ---------------------------------- | ------------------------------------------------------------ |
7+
| `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). |
88

99
## See Also
1010

docs/access_proxy.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,13 @@ int main() {
4848
std::cout << ToString(*p) << "\n"; // Prints: "123"
4949
5050
// How it works behind the scenes
51-
using Convention = std::tuple_element_t<0u, Stringable::convention_types>;
52-
using Accessor = Convention::accessor<Stringable>;
51+
using Accessor = FreeToString::accessor<Stringable, false, FreeToString, std::string()>;
5352
static_assert(std::is_base_of_v<Accessor, std::remove_reference_t<decltype(*p)>>);
5453
Accessor& a = static_cast<Accessor&>(*p);
5554
pro::proxy<Stringable>& p2 = pro::access_proxy<Stringable>(a);
5655
std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints: "true" because access_proxy converts
5756
// an accessor back to the original proxy
58-
auto result = pro::proxy_invoke<Convention, std::string()>(p2);
57+
auto result = pro::proxy_invoke<false, FreeToString, std::string()>(p2);
5958
std::cout << result << "\n"; // Prints: "123"
6059
}
6160
```

docs/basic_facade_builder/add_convention.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ The alias templates `add_convention`, `add_indirect_convention`, and `add_direct
1818
- `IC::is_direct` is `false`.
1919
- `typename IC::dispatch_type` is `D`.
2020
- `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`.
21-
- `typename IC::template accessor<F>` is `typename D::template accessor<F, IC, Os...>` if applicable.
21+
- `typename IC::template accessor<F>` is `typename D::template accessor<F, false, D, Os...>` if applicable.
2222
- `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs`, where:
2323
- `IC::is_direct` is `true`.
2424
- `typename IC::dispatch_type` is `D`.
2525
- `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`.
26-
- `typename IC::template accessor<F>` is `typename D::template accessor<F, IC, Os...>` if applicable.
26+
- `typename IC::template accessor<F>` is `typename D::template accessor<F, true, D, Os...>` if applicable.
2727
2828
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.
2929

docs/basic_facade_builder/add_reflection.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ using add_direct_reflection = basic_facade_builder</* see below */>;
1414
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,
1515

1616
- `add_reflection` is equivalent to `add_indirect_reflection`.
17-
- `add_indirect_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where:
18-
- `R2::is_direct` is `false`.
19-
- `typename R2::reflector_type` is `R`.
20-
- `typename R2::template accessor<F>` is `typename R2::template accessor<F, R2>` if applicable.
21-
- `add_direct_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where:
22-
- `R2::is_direct` is `true`.
23-
- `typename R2::reflector_type` is `R`.
24-
- `typename R2::template accessor<F>` is `typename R2::template accessor<F, R2>` if applicable.
17+
- `add_indirect_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where:
18+
- `Refl::is_direct` is `false`.
19+
- `typename Refl::reflector_type` is `R`.
20+
- `typename Refl::template accessor<F>` is `typename R::template accessor<F, false, R>` if applicable.
21+
- `add_direct_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where:
22+
- `Refl::is_direct` is `true`.
23+
- `typename Refl::reflector_type` is `R`.
24+
- `typename Refl::template accessor<F>` is `typename R::template accessor<F, true, R>` if applicable.
2525

26-
When `Rs` already contains `R2`, the template parameters shall not change.
26+
When `Rs` already contains `Refl`, the template parameters shall not change.
2727

2828
## Notes
2929

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

45-
template <class F, class R>
45+
template <class F, bool IsDirect, class R>
4646
struct accessor {
4747
const char* GetTypeName() const noexcept {
48-
const RttiReflector& self = pro::proxy_reflect<R>(pro::access_proxy<F>(*this));
48+
const RttiReflector& self = pro::proxy_reflect<IsDirect, R>(pro::access_proxy<F>(*this));
4949
return self.type_.name();
5050
}
5151
};

docs/explicit_conversion_dispatch/accessor.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
```cpp
44
// (1)
5-
template <class F, class C, class... Os>
5+
template <class F, bool IsDirect, class D, class... Os>
66
struct accessor {
77
accessor() = delete;
88
};
99

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

1717
// (3)
18-
template <class F, class C>
19-
struct accessor<F, C, T() cv ref noex> {
18+
template <class F, bool IsDirect, class D>
19+
struct accessor<F, IsDirect, D, T() cv ref noex> {
2020
explicit operator T() cv ref noex;
2121
};
2222
```
2323
2424
`(1)` The default implementation of `accessor` is not constructible.
2525
26-
`(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`.
26+
`(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`.
2727
28-
`(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)))`.
28+
`(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)))`.

docs/implicit_conversion_dispatch/accessor.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
```cpp
44
// (1)
5-
template <class F, class C, class... Os>
5+
template <class F, bool IsDirect, class D, class... Os>
66
struct accessor {
77
accessor() = delete;
88
};
99

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

1717
// (3)
18-
template <class F, class C>
19-
struct accessor<F, C, T() cv ref noex> {
18+
template <class F, bool IsDirect, class D>
19+
struct accessor<F, IsDirect, D, T() cv ref noex> {
2020
operator T() cv ref noex;
2121
};
2222
```
2323
2424
`(1)` The default implementation of `accessor` is not constructible.
2525
26-
`(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`.
26+
`(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`.
2727
28-
`(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)))`.
28+
`(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)))`.

0 commit comments

Comments
 (0)