struct accessor {
R accessibility_func_name(Args... args) cv ref noex {
- return pro::proxy_invoke(static_cast>(*this), std::forward(args)...);
+ return invoke(static_cast>(*this), std::forward(args)...);
}
};
}
diff --git a/docs/spec/PRO_DEF_FREE_DISPATCH.md b/docs/spec/PRO_DEF_FREE_DISPATCH.md
index ded5483..0bdca88 100644
--- a/docs/spec/PRO_DEF_FREE_DISPATCH.md
+++ b/docs/spec/PRO_DEF_FREE_DISPATCH.md
@@ -39,7 +39,7 @@ struct dispatch_name {
template
struct accessor {
friend R accessibility_func_name(P cv [ self, Args... args) noex {
- return pro::proxy_invoke(static_cast]>(self), std::forward(args)...);
+ return invoke(static_cast>(self), std::forward(args)...);
}
};
}
diff --git a/docs/spec/PRO_DEF_MEM_DISPATCH.md b/docs/spec/PRO_DEF_MEM_DISPATCH.md
index 2f100e4..a53f86a 100644
--- a/docs/spec/PRO_DEF_MEM_DISPATCH.md
+++ b/docs/spec/PRO_DEF_MEM_DISPATCH.md
@@ -41,7 +41,7 @@ struct dispatch_name {
template
struct accessor {
R accessibility_func_name(Args... args) cv ref noex {
- return pro::proxy_invoke(static_cast>(*this), std::forward(args)...);
+ return invoke(static_cast>(*this), std::forward(args)...);
}
};
}
diff --git a/docs/spec/ProAccessible.md b/docs/spec/ProAccessible.md
index c261217..dafa117 100644
--- a/docs/spec/ProAccessible.md
+++ b/docs/spec/ProAccessible.md
@@ -9,4 +9,4 @@ A type `T` meets the *ProAccessible* requirements of types `Args...` if the foll
## See Also
- [class template `proxy`](proxy/README.md)
-- [class template `proxy_indirect_accessor`](proxy_indirect_accessor.md)
+- [class template `proxy_indirect_accessor`](proxy_indirect_accessor/README.md)
diff --git a/docs/spec/README.md b/docs/spec/README.md
index 255903e..2d29469 100644
--- a/docs/spec/README.md
+++ b/docs/spec/README.md
@@ -28,7 +28,7 @@ This document provides the API specifications for the C++ library Proxy (version
| [`is_bitwise_trivially_relocatable`](is_bitwise_trivially_relocatable.md) | Specifies whether a type is bitwise trivially relocatable |
| [`not_implemented` ](not_implemented.md) | Exception thrown by `weak_dispatch` for the default implementation |
| [`operator_dispatch`](operator_dispatch/README.md) | Dispatch type for operator expressions with accessibility |
-| [`proxy_indirect_accessor`](proxy_indirect_accessor.md) | Provides indirection accessibility for `proxy` |
+| [`proxy_indirect_accessor`](proxy_indirect_accessor/README.md) | Provides indirection accessibility for `proxy` |
| [`proxy_view`
`observer_facade`](proxy_view.md) | Non-owning `proxy` optimized for raw pointer types |
| [`proxy`](proxy/README.md) | Wraps a pointer object matching specified facade |
| [`substitution_dispatch`](substitution_dispatch/README.md) | Dispatch type for `proxy` substitution with accessibility |
@@ -55,8 +55,8 @@ This document provides the API specifications for the C++ library Proxy (version
| [`make_proxy_shared`](make_proxy_shared.md) | Creates a `proxy` object with shared ownership |
| [`make_proxy_view`](make_proxy_view.md) | Creates a `proxy_view` object |
| [`make_proxy`](make_proxy.md) | Creates a `proxy` object potentially with heap allocation |
-| [`proxy_invoke`](proxy_invoke.md) | Invokes a `proxy` with a specified convention |
-| [`proxy_reflect`](proxy_reflect.md) | Acquires reflection information of a contained type |
+| [`proxy_invoke`](proxy_invoke.md) [deprecated] | Invokes a `proxy` with a specified convention |
+| [`proxy_reflect`](proxy_reflect.md) [deprecated] | Acquires reflection information of a contained type |
## Header ``
diff --git a/docs/spec/basic_facade_builder/.pages b/docs/spec/basic_facade_builder/.pages
index 4fbf58e..4ed3625 100644
--- a/docs/spec/basic_facade_builder/.pages
+++ b/docs/spec/basic_facade_builder/.pages
@@ -1,6 +1,7 @@
nav:
- basic_facade_builder: README.md
- add_convention
add_indirect_convention
add_direct_convention: add_convention.md
+ - add_facade_with_substitution: add_facade_with_substitution.md
- add_facade: add_facade.md
- add_reflection
add_indirect_reflection
add_direct_reflection: add_reflection.md
- add_skill: add_skill.md
diff --git a/docs/spec/basic_facade_builder/README.md b/docs/spec/basic_facade_builder/README.md
index 2ee5ea2..50a7863 100644
--- a/docs/spec/basic_facade_builder/README.md
+++ b/docs/spec/basic_facade_builder/README.md
@@ -38,6 +38,7 @@ using facade_builder =
| Name | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`add_convention`
`add_indirect_convention`
`add_direct_convention`](add_convention.md) | Adds a convention to the template parameters |
+| [`add_facade_with_substitution`](add_facade_with_substitution.md) | Adds a facade to the template parameters, together with [substitution](../substitution_dispatch/README.md) support |
| [`add_facade`](add_facade.md) | Adds a facade to the template parameters |
| [`add_reflection`
`add_indirect_reflection`
`add_direct_reflection`](add_reflection.md) | Adds a reflection to the template parameters |
| [`add_skill`](add_skill.md) | Adds a custom skill |
diff --git a/docs/spec/basic_facade_builder/add_facade.md b/docs/spec/basic_facade_builder/add_facade.md
index 2d73b5a..07f4c10 100644
--- a/docs/spec/basic_facade_builder/add_facade.md
+++ b/docs/spec/basic_facade_builder/add_facade.md
@@ -14,11 +14,13 @@ The alias template `add_facade` of `basic_facade_builder`) is deprecated. Use [`add_facade_with_substitution`](add_facade_with_substitution.md)`` instead. The single-argument form `add_facade` is not affected.
## Example
@@ -50,7 +52,7 @@ struct StringDictionary
struct MutableStringDictionary
: pro::facade_builder //
- ::add_facade //
+ ::add_facade_with_substitution //
::add_convention //
::build {};
@@ -83,4 +85,5 @@ int main() {
## See Also
+- [`add_facade_with_substitution`](add_facade_with_substitution.md)
- [`build`](build.md)
diff --git a/docs/spec/basic_facade_builder/add_facade_with_substitution.md b/docs/spec/basic_facade_builder/add_facade_with_substitution.md
new file mode 100644
index 0000000..93f90dc
--- /dev/null
+++ b/docs/spec/basic_facade_builder/add_facade_with_substitution.md
@@ -0,0 +1,53 @@
+# `basic_facade_builder::add_facade_with_substitution`
+
+> Since: 4.1.0
+
+```cpp
+template
+using add_facade_with_substitution = basic_facade_builder* see below */>;
+```
+
+The alias template `add_facade_with_substitution` of `basic_facade_builder` is equivalent to [`add_facade`](add_facade.md)``, except that it always merges a direct convention of [`substitution_dispatch`](../substitution_dispatch/README.md) into `Cs`. This convention enables substitution from a `proxy` of the built [facade](../facade.md) to a `proxy`.
+
+## Notes
+
+`add_facade_with_substitution` was introduced in `4.1.0` as a replacement for the deprecated `add_facade` syntax.
+
+The substitution convention is helpful when an API requires backward compatibility, at the cost of potentially a slightly larger binary size. When substitution is not required, use [`add_facade`](add_facade.md) to guarantee minimal binary size in code generation.
+
+## Example
+
+```cpp
+#include
+#include
+
+#include
+
+PRO_DEF_MEM_DISPATCH(MemSize, size);
+PRO_DEF_MEM_DISPATCH(MemClear, clear);
+
+struct Container : pro::facade_builder //
+ ::add_convention //
+ ::build {};
+
+// A proxy can be substituted with a proxy.
+struct ClearableContainer : pro::facade_builder //
+ ::add_facade_with_substitution //
+ ::add_convention //
+ ::build {};
+
+int main() {
+ pro::proxy p1 =
+ pro::make_proxy>(10);
+ std::cout << p1->size() << "\n"; // Prints "10"
+
+ // Substitution from an rvalue: ClearableContainer -> Container
+ pro::proxy p2 = std::move(p1);
+ std::cout << p2->size() << "\n"; // Prints "10"
+}
+```
+
+## See Also
+
+- [`add_facade`](add_facade.md)
+- [`build`](build.md)
diff --git a/docs/spec/basic_facade_builder/add_reflection.md b/docs/spec/basic_facade_builder/add_reflection.md
index 7076cc5..d34984d 100644
--- a/docs/spec/basic_facade_builder/add_reflection.md
+++ b/docs/spec/basic_facade_builder/add_reflection.md
@@ -46,12 +46,12 @@ public:
template
struct accessor {
friend std::size_t SizeOf(const P& self) noexcept {
- const LayoutReflector& refl = pro::proxy_reflect(self);
+ const LayoutReflector& refl = reflect(self);
return refl.Size;
}
friend std::size_t AlignOf(const P& self) noexcept {
- const LayoutReflector& refl = pro::proxy_reflect(self);
+ const LayoutReflector& refl = reflect(self);
return refl.Align;
}
};
diff --git a/docs/spec/explicit_conversion_dispatch/accessor.md b/docs/spec/explicit_conversion_dispatch/accessor.md
index 2bec72b..7a22671 100644
--- a/docs/spec/explicit_conversion_dispatch/accessor.md
+++ b/docs/spec/explicit_conversion_dispatch/accessor.md
@@ -25,4 +25,4 @@ struct accessor {
`(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(static_cast>(*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 invoke(static_cast>(*this))`.
diff --git a/docs/spec/implicit_conversion_dispatch/accessor.md b/docs/spec/implicit_conversion_dispatch/accessor.md
index cf871e5..15cadf3 100644
--- a/docs/spec/implicit_conversion_dispatch/accessor.md
+++ b/docs/spec/implicit_conversion_dispatch/accessor.md
@@ -25,4 +25,4 @@ struct accessor
{
`(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(static_cast>(*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 invoke(static_cast>(*this))`.
diff --git a/docs/spec/msft_lib_proxy.md b/docs/spec/msft_lib_proxy.md
index 71612e6..31906cc 100644
--- a/docs/spec/msft_lib_proxy.md
+++ b/docs/spec/msft_lib_proxy.md
@@ -10,6 +10,7 @@ Starting with 3.0.0, Proxy ships a feature-test macro that encodes the library v
| Version | Value of `__msft_lib_proxy` |
| ------- | --------------------------- |
+| 4.1.0 | `202606L` |
| 4.0.2 | `202603L` |
| 4.0.1 | `202510L` |
| 4.0.0 | `202508L` |
diff --git a/docs/spec/operator_dispatch/accessor.md b/docs/spec/operator_dispatch/accessor.md
index d35d672..c4ea650 100644
--- a/docs/spec/operator_dispatch/accessor.md
+++ b/docs/spec/operator_dispatch/accessor.md
@@ -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(static_cast>(*this), 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 invoke(static_cast>(*this), 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(static_cast>(*this))`.
+`(4)` Provides an `operator sop()` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop()` is equivalent to `return invoke(static_cast>(*this))`.
### 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(static_cast>(*this), std::forward(arg))` and returns `static_cast>(*this)`.
+`(4)` Provides an `operator sop(Arg)` with the same *cv ref noex* specifiers as of the overload type. `accessor::operator sop(Arg)` calls `invoke(static_cast>(*this), std::forward(arg))` and returns `static_cast>(*this)`.
## Right-Hand-Side Operand Specializations
@@ -94,7 +94,7 @@ struct accessor
{
}
```
-`(7)` Provides a `friend operator sop(Arg arg, P cv [ self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, P cv ][ self)` is equivalent to `return proxy_invoke(static_cast]>(self), std::forward(arg))`.
+`(7)` Provides a `friend operator sop(Arg arg, P cv [ self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, P cv ][ self)` is equivalent to `return invoke(static_cast]>(self), std::forward(arg))`.
### Assignment SOPs
@@ -108,4 +108,4 @@ struct accessor {
}
```
-`(8)` Provides a `friend operator sop(Arg arg, P cv [ self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, P cv ][ self)` calls `proxy_invoke(static_cast]>(self), std::forward(arg))` and returns `static_cast>(self)`.
+`(8)` Provides a `friend operator sop(Arg arg, P cv [ self)` with the same *noex* specifiers as of the overload type. `accessor::operator sop(Arg arg, P cv ][ self)` calls `invoke(static_cast]>(self), std::forward(arg))` and returns `static_cast>(self)`.
diff --git a/docs/spec/proxy/.pages b/docs/spec/proxy/.pages
index d405fe7..17deb33 100644
--- a/docs/spec/proxy/.pages
+++ b/docs/spec/proxy/.pages
@@ -3,10 +3,13 @@ nav:
- (constructor): constructor.md
- (destructor): destructor.md
- emplace: emplace.md
+ - invoke (non-member): friend_invoke.md
- operator bool
has_value: operator_bool.md
- operator->
operator*: indirection.md
- - operator=: assignment.md
- operator= (non-member): friend_operator_equality.md
+ - operator=: assignment.md
+ - reflect (non-member): friend_reflect.md
+ - reinterpret_invoke (non-member): friend_reinterpret_invoke.md
- reset: reset.md
- - swap: swap.md
- swap (non-member): friend_swap.md
+ - swap: swap.md
diff --git a/docs/spec/proxy/README.md b/docs/spec/proxy/README.md
index 5335fdd..5e56583 100644
--- a/docs/spec/proxy/README.md
+++ b/docs/spec/proxy/README.md
@@ -39,10 +39,13 @@ As per `facade`, `typename F::convention_types` shall be a [tuple-like](https
## Non-Member Functions
-| Name | Description |
-| ------------------------------------------- | ------------------------------------------------------------ |
-| [`operator==`](friend_operator_equality.md) | compares a `proxy` with `nullptr` |
-| [`swap`](friend_swap.md) | overload the [`std::swap`](https://en.cppreference.com/w/cpp/algorithm/swap) algorithm |
+| Name | Description |
+| ---------------------------------------------------- | ------------------------------------------------------------ |
+| [`operator==`](friend_operator_equality.md) | compares a `proxy` with `nullptr` |
+| [`swap`](friend_swap.md) | overload the [`std::swap`](https://en.cppreference.com/w/cpp/algorithm/swap) algorithm |
+| [`invoke`](friend_invoke.md) | invokes a `proxy` with a specified convention |
+| [`reflect`](friend_reflect.md) | acquires reflection information of a contained type |
+| [`reinterpret_invoke`](friend_reinterpret_invoke.md) | invokes a dispatch on a `proxy` whose contained type is known statically |
## Comparing with Other Standard Polymorphic Wrappers
diff --git a/docs/spec/proxy/friend_invoke.md b/docs/spec/proxy/friend_invoke.md
new file mode 100644
index 0000000..be6fd29
--- /dev/null
+++ b/docs/spec/proxy/friend_invoke.md
@@ -0,0 +1,63 @@
+# Function template `invoke` (`proxy`)
+
+> Since: 4.1.0
+
+```cpp
+template
+return-type-of invoke(proxy& p, Args&&... args);
+template
+return-type-of invoke(const proxy& p, Args&&... args);
+template
+return-type-of invoke(proxy&& p, Args&&... args);
+template
+return-type-of invoke(const proxy&& p, Args&&... args);
+```
+
+Invokes a `proxy` with a specified dispatch type `D`, an overload type `O`, and arguments, through a *direct* convention. Let `Args2...` be the argument types of `O`, `R` be the return type of `O`. `return-type-of` is `R`.
+
+Let `ptr` be the contained value of `p` with the same cv ref-qualifiers. Equivalent to [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D(), ptr, static_cast(args)...)`. The behavior is undefined if `p` does not contain a value.
+
+There shall be a convention type `Conv` defined in `typename F::convention_types` where
+
+- `Conv::is_direct` is `true`, and
+- `typename Conv::dispatch_type` is `D`, and
+- there shall be an overload type `O1` defined in `typename Conv::overload_types` where [`substituted-overload`](../ProOverload.md)`` is `O`.
+
+This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy` is an associated class of the arguments.
+
+To invoke an *indirect* convention, use [`invoke`](../proxy_indirect_accessor/friend_invoke.md) on the associated [`proxy_indirect_accessor`](../proxy_indirect_accessor/README.md) (i.e., on `*p`).
+
+## Notes
+
+`invoke` was introduced in `4.1.0` as a replacement for the deprecated [`proxy_invoke`](../proxy_invoke.md). `proxy_invoke` is a namespace-scope function, while `invoke` is a non-member function of `proxy` found only via argument-dependent lookup.
+
+It is generally not recommended to call `invoke` directly. Using an [`accessor`](../ProAccessible.md) is usually a better option with easier and more descriptive syntax.
+
+## Example
+
+```cpp
+#include
+#include
+
+#include
+
+PRO_DEF_MEM_DISPATCH(MemUseCount, use_count);
+
+// A direct convention operates on the contained pointer itself.
+struct SharedAware
+ : pro::facade_builder //
+ ::add_direct_convention //
+ ::build {};
+
+int main() {
+ pro::proxy p = std::make_shared(123);
+ std::cout << p.use_count() << "\n"; // Invokes with accessor, prints: "1"
+ std::cout << invoke(p)
+ << "\n"; // Invokes with the non-member invoke, also prints: "1"
+}
+```
+
+## See Also
+
+- [function template `reflect` (`proxy`)](friend_reflect.md)
+- [function template `reinterpret_invoke` (`proxy`)](friend_reinterpret_invoke.md)
diff --git a/docs/spec/proxy/friend_reflect.md b/docs/spec/proxy/friend_reflect.md
new file mode 100644
index 0000000..ad66efc
--- /dev/null
+++ b/docs/spec/proxy/friend_reflect.md
@@ -0,0 +1,75 @@
+# Function template `reflect` (`proxy`)
+
+> Since: 4.1.0
+
+```cpp
+template
+const R& reflect(const proxy& p) noexcept;
+```
+
+Acquires reflection information of the contained type of a `proxy`, through a *direct* reflection.
+
+Let `P` be the contained type of `p`. Returns a `const` reference of `R` direct-non-list-initialized with [`std::in_place_type`](https://en.cppreference.com/w/cpp/utility/in_place). The behavior is undefined if `p` does not contain a value.
+
+There shall be a reflection type `Refl` defined in `typename F::reflection_types` where
+
+- `Refl::is_direct` is `true`, and
+- `typename Refl::reflector_type` is `R`.
+
+The reference obtained from `reflect()` may be invalidated if `p` is subsequently modified.
+
+This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy` is an associated class of the arguments.
+
+To acquire an *indirect* reflection (deduced from the pointed-to type), use [`reflect`](../proxy_indirect_accessor/friend_reflect.md) on the associated [`proxy_indirect_accessor`](../proxy_indirect_accessor/README.md) (i.e., on `*p`).
+
+## Notes
+
+`reflect` was introduced in `4.1.0` as a replacement for the deprecated [`proxy_reflect`](../proxy_reflect.md). `proxy_reflect` is a namespace-scope function, while `reflect` is a non-member function of `proxy` found only via argument-dependent lookup.
+
+This function is useful when only metadata deduced from a type is needed. While [`invoke`](friend_invoke.md) can also retrieve type metadata, `reflect` can generate more efficient code in this context.
+
+## Example
+
+```cpp
+#include
+#include
+#include
+
+#include
+
+class CopyabilityReflector {
+public:
+ template
+ constexpr explicit CopyabilityReflector(std::in_place_type_t)
+ : copyable_(std::is_copy_constructible_v) {}
+
+ template
+ struct accessor {
+ bool IsCopyable() const noexcept {
+ const CopyabilityReflector& self =
+ reflect(static_cast(*this));
+ return self.copyable_;
+ }
+ };
+
+private:
+ bool copyable_;
+};
+
+struct CopyabilityAware : pro::facade_builder //
+ ::add_direct_reflection //
+ ::build {};
+
+int main() {
+ pro::proxy p1 = std::make_unique();
+ std::cout << std::boolalpha << p1.IsCopyable() << "\n"; // Prints "false"
+
+ pro::proxy p2 = std::make_shared();
+ std::cout << p2.IsCopyable() << "\n"; // Prints "true"
+}
+```
+
+## See Also
+
+- [function template `invoke` (`proxy`)](friend_invoke.md)
+- [alias template `basic_facade_builder::add_reflection`](../basic_facade_builder/add_reflection.md)
diff --git a/docs/spec/proxy/friend_reinterpret_invoke.md b/docs/spec/proxy/friend_reinterpret_invoke.md
new file mode 100644
index 0000000..ee98869
--- /dev/null
+++ b/docs/spec/proxy/friend_reinterpret_invoke.md
@@ -0,0 +1,60 @@
+# Function template `reinterpret_invoke` (`proxy`)
+
+> Since: 4.1.0
+
+```cpp
+template
+R reinterpret_invoke(proxy& p, Args&&... args);
+template
+R reinterpret_invoke(const proxy& p, Args&&... args);
+template
+R reinterpret_invoke(proxy&& p, Args&&... args);
+template
+R reinterpret_invoke(const proxy&& p, Args&&... args);
+```
+
+Invokes a dispatch on the value contained in a `proxy`, reinterpreting the underlying storage as a caller-specified pointer type `P`. `D` is a dispatch type, `R` is the return type, and `Args...` are the argument types forwarded to the dispatch.
+
+Let `ptr` be the contained value of `p`, with the same cv ref-qualifiers as `p`. **The behavior is undefined unless `p` contains a value whose type is `P`.** Equivalent to [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D(), ptr, std::forward(args)...)`.
+
+This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy` is an associated class of the arguments. To reinterpret-invoke through the pointed-to value, use [`reinterpret_invoke`](../proxy_indirect_accessor/friend_reinterpret_invoke.md) on the associated [`proxy_indirect_accessor`](../proxy_indirect_accessor/README.md) (i.e., on `*p`).
+
+## Notes
+
+`reinterpret_invoke` is a low-level primitive. In contrast to [`invoke`](friend_invoke.md), it performs **no type erasure**: it neither consults the runtime metadata of the `proxy` nor requires `D` to correspond to a convention registered in `typename F::convention_types`. Instead, the caller names the exact contained pointer type `P`, and the implementation reinterprets the `proxy`'s storage as `P` directly. This avoids the indirection of a virtual call, at the cost of requiring the contained type to be known statically — supplying a `P` that does not match the contained value is undefined behavior.
+
+For ordinary use, prefer an [`accessor`](../ProAccessible.md) or [`invoke`](friend_invoke.md), which are type-erased and do not require the caller to know the contained type. `reinterpret_invoke` is intended for advanced scenarios, such as implementing custom dispatch types or [accessors](../ProAccessible.md), where the concrete pointer type is already known.
+
+## Example
+
+```cpp
+#include
+#include
+
+#include
+
+PRO_DEF_MEM_DISPATCH(MemUseCount, use_count);
+
+struct SharedAware
+ : pro::facade_builder //
+ ::add_direct_convention //
+ ::build {};
+
+int main() {
+ pro::proxy p =
+ std::make_shared(123); // The contained pointer type is shared_ptr
+
+ // Type-erased invocation via the runtime metadata of `p`:
+ std::cout << invoke(p) << "\n"; // "1"
+
+ // Low-level invocation: we already know `p` holds a `std::shared_ptr`,
+ // so reinterpret the storage and dispatch directly, with no virtual call:
+ std::cout << reinterpret_invoke, MemUseCount, long>(p)
+ << "\n"; // Also prints "1"
+}
+```
+
+## See Also
+
+- [function template `invoke` (`proxy`)](friend_invoke.md)
+- [named requirements *ProDispatch*](../ProDispatch.md)
diff --git a/docs/spec/proxy/indirection.md b/docs/spec/proxy/indirection.md
index 4bcdf1f..a1dd8ef 100644
--- a/docs/spec/proxy/indirection.md
+++ b/docs/spec/proxy/indirection.md
@@ -58,4 +58,4 @@ int main() {
## See Also
-- [class template `proxy_indirect_accessor`](../proxy_indirect_accessor.md)
+- [class template `proxy_indirect_accessor`](../proxy_indirect_accessor/README.md)
diff --git a/docs/spec/proxy_indirect_accessor.md b/docs/spec/proxy_indirect_accessor.md
deleted file mode 100644
index ddb4c2a..0000000
--- a/docs/spec/proxy_indirect_accessor.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Class template `proxy_indirect_accessor`
-
-> Header: `proxy.h`
-> Module: `proxy`
-> Namespace: `pro::inline v4`
-> Since: 3.2.0
-
-```cpp
-template
-class proxy_indirect_accessor;
-```
-
-Class template `proxy_indirect_accessor` provides indirection accessibility for `proxy`. 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 `C` in `Cs`, if `C::is_direct` is `false` and `typename C::dispatch_type` meets the [*ProAccessible* requirements](ProAccessible.md) of `proxy_indirect_accessor, typename C::dispatch_type, substituted-overload-types...`, `typename C::dispatch_type::template accessor, typename C::dispatch_type, substituted-overload-types...>` is inherited by `proxy_indirect_accessor`. Let `Os...` be the element types of `typename C::overload_types`, `substituted-overload-types...` is [`substituted-overload...`](ProOverload.md).
-- For each type `R` in `Rs`, if `R::is_direct` is `false` and `typename R::reflector_type` meets the [*ProAccessible* requirements](ProAccessible.md) of `proxy_indirect_accessor, typename R::reflector_type`, `typename R::reflector_type::template accessor, typename R::reflector_type` is inherited by `proxy_indirect_accessor`.
-
-## Member Functions
-
-| Name | Description |
-| ----------------------- | ----------------------------------------- |
-| (constructor) [deleted] | Has neither default nor copy constructors |
-
-## See also
-
-- [function template `proxy_invoke`](proxy_invoke.md)
-- [function template `proxy_reflect`](proxy_reflect.md)
diff --git a/docs/spec/proxy_indirect_accessor/.pages b/docs/spec/proxy_indirect_accessor/.pages
new file mode 100644
index 0000000..8ae8f61
--- /dev/null
+++ b/docs/spec/proxy_indirect_accessor/.pages
@@ -0,0 +1,5 @@
+nav:
+ - proxy_indirect_accessor: README.md
+ - invoke: friend_invoke.md
+ - reflect: friend_reflect.md
+ - reinterpret_invoke: friend_reinterpret_invoke.md
diff --git a/docs/spec/proxy_indirect_accessor/README.md b/docs/spec/proxy_indirect_accessor/README.md
new file mode 100644
index 0000000..fbab8dc
--- /dev/null
+++ b/docs/spec/proxy_indirect_accessor/README.md
@@ -0,0 +1,34 @@
+# Class template `proxy_indirect_accessor`
+
+> Header: `proxy.h`
+> Module: `proxy`
+> Namespace: `pro::inline v4`
+> Since: 3.2.0
+
+```cpp
+template
+class proxy_indirect_accessor;
+```
+
+Class template `proxy_indirect_accessor` provides indirection accessibility for `proxy`. 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 `C` in `Cs`, if `C::is_direct` is `false` and `typename C::dispatch_type` meets the [*ProAccessible* requirements](../ProAccessible.md) of `proxy_indirect_accessor, typename C::dispatch_type, substituted-overload-types...`, `typename C::dispatch_type::template accessor, typename C::dispatch_type, substituted-overload-types...>` is inherited by `proxy_indirect_accessor`. Let `Os...` be the element types of `typename C::overload_types`, `substituted-overload-types...` is [`substituted-overload...`](../ProOverload.md).
+- For each type `R` in `Rs`, if `R::is_direct` is `false` and `typename R::reflector_type` meets the [*ProAccessible* requirements](../ProAccessible.md) of `proxy_indirect_accessor, typename R::reflector_type`, `typename R::reflector_type::template accessor, typename R::reflector_type` is inherited by `proxy_indirect_accessor`.
+
+## Member Functions
+
+| Name | Description |
+| ----------------------- | ----------------------------------------- |
+| (constructor) [deleted] | Has neither default nor copy constructors |
+
+## Non-Member Functions
+
+| Name | Description |
+| ---------------------------------------------------- | ------------------------------------------------------------ |
+| [`invoke`](friend_invoke.md) | invokes a `proxy` with a specified convention |
+| [`reflect`](friend_reflect.md) | acquires reflection information of a contained type |
+| [`reinterpret_invoke`](friend_reinterpret_invoke.md) | invokes a dispatch on a `proxy` whose contained type is known statically |
+
+## See also
+
+- [class template `proxy`](../proxy/README.md)
diff --git a/docs/spec/proxy_indirect_accessor/friend_invoke.md b/docs/spec/proxy_indirect_accessor/friend_invoke.md
new file mode 100644
index 0000000..0a5e9f1
--- /dev/null
+++ b/docs/spec/proxy_indirect_accessor/friend_invoke.md
@@ -0,0 +1,62 @@
+# Function template `invoke` (`proxy_indirect_accessor`)
+
+> Since: 4.1.0
+
+```cpp
+template
+return-type-of invoke(proxy_indirect_accessor& p, Args&&... args);
+template
+return-type-of invoke(const proxy_indirect_accessor& p, Args&&... args);
+template
+return-type-of invoke(proxy_indirect_accessor&& p, Args&&... args);
+template
+return-type-of invoke(const proxy_indirect_accessor&& p, Args&&... args);
+```
+
+Invokes a `proxy_indirect_accessor` with a specified dispatch type `D`, an overload type `O`, and arguments, through an *indirect* convention. Let `Args2...` be the argument types of `O`, `R` be the return type of `O`. `return-type-of` is `R`.
+
+Let `ptr` be the contained value of the `proxy` object associated to `p` with the same cv ref-qualifiers. Equivalent to [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D(), *ptr, static_cast(args)...)`.
+
+There shall be a convention type `Conv` defined in `typename F::convention_types` where
+
+- `Conv::is_direct` is `false`, and
+- `typename Conv::dispatch_type` is `D`, and
+- there shall be an overload type `O1` defined in `typename Conv::overload_types` where [`substituted-overload`](../ProOverload.md)`` is `O`.
+
+This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy_indirect_accessor` is an associated class of the arguments.
+
+A `proxy_indirect_accessor` is obtained by dereferencing a [`proxy`](../proxy/README.md) (i.e., `*p`). To invoke a *direct* convention, use [`invoke`](../proxy/friend_invoke.md) on the [`proxy`](../proxy/README.md) itself.
+
+## Notes
+
+`invoke` was introduced in `4.1.0` as a replacement for the deprecated [`proxy_invoke`](../proxy_invoke.md). `proxy_invoke` is a namespace-scope function, while `invoke` is a non-member function of `proxy_indirect_accessor` found only via argument-dependent lookup.
+
+It is generally not recommended to call `invoke` directly. Using an [`accessor`](../ProAccessible.md) is usually a better option with easier and more descriptive syntax.
+
+## Example
+
+```cpp
+#include
+#include
+
+#include
+
+PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString);
+
+struct Stringable : pro::facade_builder //
+ ::add_convention //
+ ::build {};
+
+int main() {
+ int a = 123;
+ pro::proxy p = &a;
+ std::cout << ToString(*p) << "\n"; // Invokes with accessor, prints: "123"
+ std::cout << invoke(*p)
+ << "\n"; // Invokes with the non-member invoke, also prints: "123"
+}
+```
+
+## See Also
+
+- [function template `reflect` (`proxy_indirect_accessor`)](friend_reflect.md)
+- [function template `reinterpret_invoke` (`proxy_indirect_accessor`)](friend_reinterpret_invoke.md)
diff --git a/docs/spec/proxy_indirect_accessor/friend_reflect.md b/docs/spec/proxy_indirect_accessor/friend_reflect.md
new file mode 100644
index 0000000..bb16387
--- /dev/null
+++ b/docs/spec/proxy_indirect_accessor/friend_reflect.md
@@ -0,0 +1,69 @@
+# Function template `reflect` (`proxy_indirect_accessor`)
+
+> Since: 4.1.0
+
+```cpp
+template
+const R& reflect(const proxy_indirect_accessor& p) noexcept;
+```
+
+Acquires reflection information of the contained type of the associated `proxy`, through an *indirect* reflection.
+
+Let `P` be the contained type of the `proxy` object associated to `p`. Returns a `const` reference of `R` direct-non-list-initialized with [`std::in_place_type::element_type>`](https://en.cppreference.com/w/cpp/utility/in_place).
+
+There shall be a reflection type `Refl` defined in `typename F::reflection_types` where
+
+- `Refl::is_direct` is `false`, and
+- `typename Refl::reflector_type` is `R`.
+
+The reference obtained from `reflect()` may be invalidated if the associated `proxy` is subsequently modified.
+
+This function is not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy_indirect_accessor` is an associated class of the arguments.
+
+A `proxy_indirect_accessor` is obtained by dereferencing a [`proxy`](../proxy/README.md) (i.e., `*p`). To acquire a *direct* reflection (deduced from the pointer type), use [`reflect`](../proxy/friend_reflect.md) on the [`proxy`](../proxy/README.md) itself.
+
+## Notes
+
+`reflect` was introduced in `4.1.0` as a replacement for the deprecated [`proxy_reflect`](../proxy_reflect.md). `proxy_reflect` is a namespace-scope function, while `reflect` is a non-member function of `proxy_indirect_accessor` found only via argument-dependent lookup.
+
+This function is useful when only metadata deduced from a type is needed. While [`invoke`](friend_invoke.md) can also retrieve type metadata, `reflect` can generate more efficient code in this context.
+
+## Example
+
+```cpp
+#include
+
+#include
+
+class LayoutReflector {
+public:
+ template
+ constexpr explicit LayoutReflector(std::in_place_type_t)
+ : Size(sizeof(T)), Align(alignof(T)) {}
+
+ template
+ struct accessor {
+ friend std::size_t SizeOf(const P& self) noexcept {
+ const LayoutReflector& refl = reflect(self);
+ return refl.Size;
+ }
+ };
+
+ std::size_t Size, Align;
+};
+
+struct LayoutAware : pro::facade_builder //
+ ::add_indirect_reflection //
+ ::build {};
+
+int main() {
+ int a = 123;
+ pro::proxy p = &a;
+ std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int), the pointed-to type
+}
+```
+
+## See Also
+
+- [function template `invoke` (`proxy_indirect_accessor`)](friend_invoke.md)
+- [alias template `basic_facade_builder::add_reflection`](../basic_facade_builder/add_reflection.md)
diff --git a/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md b/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md
new file mode 100644
index 0000000..0d0ca6c
--- /dev/null
+++ b/docs/spec/proxy_indirect_accessor/friend_reinterpret_invoke.md
@@ -0,0 +1,60 @@
+# Function template `reinterpret_invoke` (`proxy_indirect_accessor`)
+
+> Since: 4.1.0
+
+```cpp
+template
+R reinterpret_invoke(proxy_indirect_accessor& p, Args&&... args);
+template
+R reinterpret_invoke(const proxy_indirect_accessor