` | A nullable type `S` meeting the [*ProBasicMetadata* requirements](ProBasicMetadata.md). |
+
+Let `ci` be a value of type `const I`, `ctx` be a value of type `Ctx`, `args...` be values of type `Args...`, `s` be a value of type `S`, and `cs` be a value of type `const S`. The following expressions shall be well-formed and have the specified semantics.
+
+| Expressions | Semantics |
+| -------------------------------------- | ------------------------------------------------------------ |
+| `I(std::in_place_type)` | Creates an object of type `I` that holds an invoker of `P`, shall not throw. |
+| `ci(ctx, std::forward(args)...)` | Has the same effect as `invoke(ctx, std::forward(args)...)`, where `P` is the type `ci` was created with, and the return type is `R`. Shall not throw when `O` is a `noexcept` overload. The behavior is undefined when `ci` holds no invoker. |
+| `S(std::in_place_type)` | Creates an object of type `S` that holds the metadata `M(std::in_place_type
)`, shall not throw. |
+| `*cs` | A `const M&` referring to the metadata held by `cs`. The behavior is undefined when `cs` holds no metadata. |
+| `s = cs2` | Where `cs2` is a value of type `const MP::template storage`, for some type `M2` whose `const M2&` is [nothrow-convertible](https://en.cppreference.com/w/cpp/types/is_convertible) to `const M&`. Replaces the metadata of `s` with the metadata of `cs2` converted to `M`, shall not throw. The behavior is undefined when `cs2` holds no metadata. |
+
+## Notes
+
+`I` is required not to be final because `proxy` composes the invokers of all the conventions of a facade into a single metadata object by inheritance.
+
+The last expression is what makes a conversion to a super well-formed. The metadata of a super is reachable from the metadata of the deriving facade, so assigning the latter to the former transfers the invokers the super needs.
+
+The metadata type of a [`proxy`](proxy/README.md)`` depends on both `F` and `MP`, so a `proxy` converts only to a `proxy` with the same metadata policy. The metadata policy is therefore chosen once, where the `proxy` type is named, and every conversion from that point on stays within it.
+
+## See Also
+
+- [class `compact_metadata`
class `inline_metadata`](compact_metadata.md)
+- [*ProBasicMetadata* requirements](ProBasicMetadata.md)
+- [*ProMetadata* requirements](ProMetadata.md)
diff --git a/docs/spec/ProOverload.md b/docs/spec/ProOverload.md
index 3f02d53..40010bc 100644
--- a/docs/spec/ProOverload.md
+++ b/docs/spec/ProOverload.md
@@ -1,11 +1,11 @@
# Named requirements: *ProOverload*
-A type `O` meets the *ProOverload* requirements if `substituted-overload` matches one of the following definitions, where `F` is any type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), `R` is the *return type*, `Args...` are the *argument types*.
+A type `O` meets the *ProOverload* requirements if `substituted-overload` matches one of the following definitions, where `F` is any type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), `MP` is any type meeting the [*ProMetadataPolicy* requirements](ProMetadataPolicy.md), `R` is the *return type*, `Args...` are the *argument types*.
-The exposition-only type `substituted-overload` is `OT` if `O` is a specialization of [`facade_aware_overload_t`](facade_aware_overload_t.md), or `O` otherwise.
+*Since 5.0.0*: the exposition-only type `substituted-overload` is `OT` if `O` is a specialization of [`proxy_dependent_signature`](proxy_dependent_signature.md), or `O` otherwise. Previously the exposition-only type was `substituted-overload`, and `OT` was instantiated with `F` only.
-| Definitions of `substituted-overload` |
-| ------------------------------------------- |
+| Definitions of `substituted-overload` |
+| ----------------------------------------------- |
| `R(Args...)` |
| `R(Args...) noexcept` |
| `R(Args...) &` |
@@ -22,4 +22,5 @@ The exposition-only type `substituted-overload` is `OT` if `O` is a spe
## See Also
- [*ProConvention* requirements](ProConvention.md)
+- [*ProMetadataPolicy* requirements](ProMetadataPolicy.md)
- [class template `std::move_only_function`](https://en.cppreference.com/w/cpp/utility/functional/move_only_function)
diff --git a/docs/spec/ProReflection.md b/docs/spec/ProReflection.md
index 7878144..9fbdc9f 100644
--- a/docs/spec/ProReflection.md
+++ b/docs/spec/ProReflection.md
@@ -6,9 +6,9 @@ A type `R` meets the *ProReflection* requirements of a type `P` if `R` meets the
| Expressions | Semantics |
| --------------------------------------------------- | ------------------------------------------------------------ |
-| `typename R::reflector_type(std::in_place_type)` | Constructs a value of type `typename R::reflector_type`, reflecting implementation-defined metadata of type `T`. `typename R::reflector_type` shall meet the [*ProMeta* requirements](ProMeta.md) of `T` *(since 5.0.0)*. |
+| `typename R::reflector_type(std::in_place_type)` | Constructs a value of type `typename R::reflector_type`, reflecting implementation-defined metadata of type `T`. `typename R::reflector_type` shall meet the [*ProMetadata* requirements](ProMetadata.md) of `T` *(since 5.0.0)*. |
## See Also
- [*ProFacade* requirements](ProFacade.md)
-- [*ProMeta* requirements](ProMeta.md)
+- [*ProMetadata* requirements](ProMetadata.md)
diff --git a/docs/spec/README.md b/docs/spec/README.md
index 4254cd1..390d201 100644
--- a/docs/spec/README.md
+++ b/docs/spec/README.md
@@ -21,13 +21,14 @@ This document provides the API specifications for the C++ library Proxy (version
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`bad_proxy_cast`](bad_proxy_cast.md) | Exception thrown by the value-returning forms of `proxy_cast` on a type mismatch |
| [`basic_facade_builder`
`facade_builder`](basic_facade_builder/README.md) | Provides capability to build a facade type at compile-time |
+| [`compact_metadata`
`inline_metadata`](compact_metadata.md) | The metadata policies provided by the library |
| [`constraint_level`](constraint_level.md) | Defines the 4 constraint levels of a special member function |
| [`explicit_conversion_dispatch`
`conversion_dispatch`](explicit_conversion_dispatch/README.md) | Dispatch type for explicit conversion expressions with accessibility |
-| [`facade_aware_overload_t`](facade_aware_overload_t.md) | Specifies a facade-aware overload template |
| [`implicit_conversion_dispatch`](implicit_conversion_dispatch/README.md) | Dispatch type for implicit conversion expressions with accessibility |
| [`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_dependent_signature`](proxy_dependent_signature.md) | Specifies a proxy-dependent signature template |
| [`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 |
@@ -85,9 +86,12 @@ Also included in `proxy.h`.
| [*ProAccessible*](ProAccessible.md) | Specifies that a type provides accessibility to `proxy` |
| [*ProBasicConvention*](ProBasicConvention.md) | Specifies that a type potentially models a "convention" |
| [*ProBasicFacade*](ProBasicFacade.md) | Specifies that a type potentially models a "facade" of `proxy` |
+| [*ProBasicMetadata*](ProBasicMetadata.md) | Specifies that a type potentially models "metadata" |
| [*ProBasicReflection*](ProBasicReflection.md) | Specifies that a type potentially models a "reflection" |
| [*ProConvention*](ProConvention.md) | Specifies that a type models a "convention" |
| [*ProDispatch*](ProDispatch.md) | Specifies that a type models a "dispatch" |
| [*ProFacade*](ProFacade.md) | Specifies that a type models a "facade" of `proxy` |
+| [*ProMetadata*](ProMetadata.md) | Specifies that a type models "metadata" of a type |
+| [*ProMetadataPolicy*](ProMetadataPolicy.md) | Specifies that a type models a "metadata policy" of `proxy` |
| [*ProOverload*](ProOverload.md) | Specifies that a type models an "overload" |
| [*ProReflection*](ProReflection.md) | Specifies that a type models a "reflection" |
diff --git a/docs/spec/allocate_proxy.md b/docs/spec/allocate_proxy.md
index c2436a1..e0b75c9 100644
--- a/docs/spec/allocate_proxy.md
+++ b/docs/spec/allocate_proxy.md
@@ -12,21 +12,25 @@ template
proxy allocate_proxy(const Alloc& alloc, T&& value); // freestanding-deleted
// (2)
-template
-proxy allocate_proxy(const Alloc& alloc, Args&&... args); // freestanding-deleted
+template
+proxy allocate_proxy(const Alloc& alloc, Args&&... args); // freestanding-deleted
// (3)
-template
-proxy allocate_proxy(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted
+template
+proxy allocate_proxy(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted
```
+Let `MP` be the [metadata policy](ProMetadataPolicy.md) of the created `proxy`, which is [`compact_metadata`](compact_metadata.md) for `(1)`.
+
`(1)` Creates a `proxy` object containing a value `p` of type *allocated-ptr<*`std::decay_t`*, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(value)`.
-`(2)` Creates a `proxy` object containing a value `p` of type *allocated-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+`(2)` Creates a `proxy` object containing a value `p` of type *allocated-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+
+`(3)` Creates a `proxy` object containing a value `p` of type *allocated-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
-`(3)` Creates a `proxy` object containing a value `p` of type *allocated-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
+*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F, MP>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
-*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+*Since 5.0.0*: `(2-3)` can name the metadata policy of the created `proxy`. `(1)` deduces the target type, so it always uses the default policy, and a `proxy` with another policy is created by naming the target type as well.
## Return Value
diff --git a/docs/spec/allocate_proxy_shared.md b/docs/spec/allocate_proxy_shared.md
index 84b90dd..b40aed8 100644
--- a/docs/spec/allocate_proxy_shared.md
+++ b/docs/spec/allocate_proxy_shared.md
@@ -13,21 +13,25 @@ template
proxy allocate_proxy_shared(const Alloc& alloc, T&& value); // freestanding-deleted
// (2)
-template
-proxy allocate_proxy_shared(const Alloc& alloc, Args&&... args); // freestanding-deleted
+template
+proxy allocate_proxy_shared(const Alloc& alloc, Args&&... args); // freestanding-deleted
// (3)
-template
-proxy allocate_proxy_shared(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted
+template
+proxy allocate_proxy_shared(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted
```
+Let `MP` be the [metadata policy](ProMetadataPolicy.md) of the created `proxy`, which is [`compact_metadata`](compact_metadata.md) for `(1)`.
+
`(1)` Creates a `proxy` object containing a value `p` of type *strong-compact-ptr<*`std::decay_t`*, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(value)`.
-`(2)` Creates a `proxy` object containing a value `p` of type *strong-compact-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+`(2)` Creates a `proxy` object containing a value `p` of type *strong-compact-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+
+`(3)` Creates a `proxy` object containing a value `p` of type *strong-compact-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
-`(3)` Creates a `proxy` object containing a value `p` of type *strong-compact-ptr<T, Alloc>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
+For `(1-3)`, if [`proxiable_target, F, MP>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
-For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+*Since 5.0.0*: `(2-3)` can name the metadata policy of the created `proxy`. `(1)` deduces the target type, so it always uses the default policy, and a `proxy` with another policy is created by naming the target type as well.
## Return Value
diff --git a/docs/spec/basic_facade_builder/add_facade.md b/docs/spec/basic_facade_builder/add_facade.md
index 2a5eb07..eb77e87 100644
--- a/docs/spec/basic_facade_builder/add_facade.md
+++ b/docs/spec/basic_facade_builder/add_facade.md
@@ -20,7 +20,7 @@ The alias template `add_facade` of `basic_facade_builder` needs no indirect call to translate the metadata. The contained value is still copied or relocated as it would be by a copy or a move of a `proxy` of the built facade, which involves an indirect call unless the corresponding [`constraint_level`](../constraint_level.md) is `trivial`. Two consequences of embedding are worth noting. When a super is reachable through more than one other super (a diamond), its metadata is embedded once per path. When the built facade strengthens a [`constraint_level`](../constraint_level.md) that `F` also declares (for example from `nontrivial` to `nothrow`), both levels are represented. Either case makes the metadata larger than the sum of the distinct conventions, and nesting diamonds compounds the effect. Metadata of that size is held out of line and shared by every `proxy` of the facade, so the cost is in static data rather than in `sizeof(proxy)`.
diff --git a/docs/spec/compact_metadata.md b/docs/spec/compact_metadata.md
new file mode 100644
index 0000000..3d6fd69
--- /dev/null
+++ b/docs/spec/compact_metadata.md
@@ -0,0 +1,61 @@
+# Class `compact_metadata`
Class `inline_metadata`
+
+> Header: `proxy.h`
+> Module: `proxy`
+> Namespace: `pro::inline v5`
+> Since: 5.0.0
+
+```cpp
+struct compact_metadata;
+struct inline_metadata;
+```
+
+`compact_metadata` and `inline_metadata` are the metadata policies provided by the library. Both meet the [*ProMetadataPolicy* requirements](ProMetadataPolicy.md) and erase an invocation the same way. They differ only in how a [`proxy`](proxy/README.md) keeps the metadata deduced from the contained type.
+
+| Name | Metadata storage |
+| ------------------ | ------------------------------------------------------------ |
+| `compact_metadata` | The metadata is kept in the `proxy` object when it is no larger than a pointer, and otherwise the `proxy` keeps a pointer to a static metadata object of the contained type. |
+| `inline_metadata` | The metadata is always kept in the `proxy` object. |
+
+`compact_metadata` is the default metadata policy of `proxy` and of every function template that creates a `proxy`.
+
+A `proxy` converts only to a `proxy` with the same metadata policy, so the policy is chosen where the `proxy` type is named and is preserved by every conversion to a super, by [`skills::as_view`](skills_as_view.md), by [`skills::as_weak`](skills_as_weak.md) and by [`weak_proxy::lock`](weak_proxy.md).
+
+## Notes
+
+`inline_metadata` trades size for one fewer indirection on every invocation. A `proxy` with `inline_metadata` is as large as its pointer storage plus its whole metadata, while an invocation reads the invoker directly from the `proxy` instead of following a pointer to a static metadata object. `compact_metadata` keeps `sizeof(proxy)` at the size of the pointer storage plus one pointer, at the cost of that indirection when the metadata is larger than a pointer.
+
+The indirection of `compact_metadata` costs more than one load when the `proxy` is long-lived and invoked from a cold path. The static metadata object lives away from the `proxy`, so reaching it touches a cache line the caller would not otherwise bring in, while inline metadata rides in the lines already fetched for the `proxy` itself. `inline_metadata` is aimed at that case, and at latency-sensitive code in general, rather than at throughput in a hot loop where the static object stays cached.
+
+## Example
+
+```cpp
+#include
+#include
+
+#include
+
+PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString);
+
+struct Stringable : pro::facade_builder //
+ ::add_convention //
+ ::support_copy //
+ ::build {};
+
+int main() {
+ pro::proxy p1 = pro::make_proxy(123);
+ pro::proxy p2 =
+ pro::make_proxy(123);
+ std::cout << ToString(*p1) << "\n"; // Prints "123"
+ std::cout << ToString(*p2) << "\n"; // Prints "123"
+
+ // Keeping the metadata inline makes the proxy larger
+ std::cout << std::boolalpha << (sizeof(p2) > sizeof(p1))
+ << "\n"; // Prints "true"
+}
+```
+
+## See Also
+
+- [class template `proxy`](proxy/README.md)
+- [*ProMetadataPolicy* requirements](ProMetadataPolicy.md)
diff --git a/docs/spec/facade_aware_overload_t.md b/docs/spec/facade_aware_overload_t.md
deleted file mode 100644
index f100402..0000000
--- a/docs/spec/facade_aware_overload_t.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# Class template `facade_aware_overload_t`
-
-> Header: `proxy.h`
-> Module: `proxy`
-> Namespace: `pro::inline v5`
-> Since: 3.2.1
-
-```cpp
-template class O>
-struct facade_aware_overload_t { facade_aware_overload_t() = delete; };
-```
-
-Class template `facade_aware_overload_t` specifies a facade-aware overload template `O`. It is useful when modeling an [overload](ProOverload.md) type of a [facade](facade.md) type that recursively depends on the facade type itself.
-
-## Notes
-
-`facade_aware_overload_t` can be used to define a convention in a base facade type, and is portable to the definition of another facade type via [`basic_facade_builder::add_facade`](basic_facade_builder/add_facade.md). It can also effectively avoid a facade type being implicitly instantiated when it is incomplete.
-
-## Example
-
-```cpp
-#include
-
-#include
-
-template
-using BinaryOverload =
- pro::proxy(const pro::proxy_indirect_accessor& rhs) const;
-
-template
-pro::proxy operator+(const T& value,
- const pro::proxy_indirect_accessor& rhs)
- requires(!std::is_same_v>)
-{
- return pro::make_proxy(value + proxy_cast(rhs));
-}
-
-struct Addable
- : pro::facade_builder //
- ::add_skill //
- ::add_skill //
- ::add_convention,
- pro::facade_aware_overload_t> //
- ::build {};
-
-int main() {
- pro::proxy p1 = pro::make_proxy(1);
- pro::proxy p2 = pro::make_proxy(2);
- pro::proxy p3 = *p1 + *p2;
- std::cout << std::format("{}\n", *p3); // Prints "3"
-}
-```
-
-## See Also
-
-- [*ProOverload* requirements](ProOverload.md)
-- [alias template `skills::as_view`](skills_as_view.md)
diff --git a/docs/spec/inplace_proxiable_target.md b/docs/spec/inplace_proxiable_target.md
index c93d5fc..40f888f 100644
--- a/docs/spec/inplace_proxiable_target.md
+++ b/docs/spec/inplace_proxiable_target.md
@@ -5,8 +5,8 @@
> Namespace: `pro::inline v5`
```cpp
-template
-concept inplace_proxiable_target = proxiable, F>;
+template
+concept inplace_proxiable_target = proxiable, F, MP>;
```
See [`make_proxy_inplace`](make_proxy_inplace.md) for the definition of the exposition-only class template *inplace-ptr*.
diff --git a/docs/spec/make_proxy.md b/docs/spec/make_proxy.md
index 561d8e5..680291a 100644
--- a/docs/spec/make_proxy.md
+++ b/docs/spec/make_proxy.md
@@ -7,12 +7,12 @@
The definitions of `make_proxy` make use of the following exposition-only function:
```cpp
-template
-proxy make-proxy-internal(Args&&... args) {
- if constexpr (inplace_proxiable_target) {
- return make_proxy_inplace(std::forward(args)...);
+template
+proxy make-proxy-internal(Args&&... args) {
+ if constexpr (inplace_proxiable_target) {
+ return make_proxy_inplace(std::forward(args)...);
} else {
- return allocate_proxy(std::allocator{}, std::forward(args)...);
+ return allocate_proxy(std::allocator{}, std::forward(args)...);
}
}
```
@@ -23,21 +23,25 @@ template
proxy make_proxy(T&& value); // freestanding-deleted
// (2)
-template
-proxy make_proxy(Args&&... args); // freestanding-deleted
+template
+proxy make_proxy(Args&&... args); // freestanding-deleted
// (3)
-template
-proxy make_proxy(std::initializer_list il, Args&&... args); // freestanding-deleted
+template
+proxy make_proxy(std::initializer_list il, Args&&... args); // freestanding-deleted
```
-`(1)` Equivalent to `return make-proxy-internal>(std::forward(value))`.
+Let `MP` be the [metadata policy](ProMetadataPolicy.md) of the created `proxy`, which is [`compact_metadata`](compact_metadata.md) for `(1)`.
-`(2)` Equivalent to `return make-proxy-internal(std::forward(args)...)`.
+`(1)` Equivalent to `return make-proxy-internal>(std::forward(value))`.
-`(3)` Equivalent to `return make-proxy-internal(il, std::forward(args)...)`.
+`(2)` Equivalent to `return make-proxy-internal(std::forward(args)...)`.
-*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+`(3)` Equivalent to `return make-proxy-internal(il, std::forward(args)...)`.
+
+*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F, MP>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+
+*Since 5.0.0*: `(2-3)` can name the metadata policy of the created `proxy`. `(1)` deduces the target type, so it always uses the default policy, and a `proxy` with another policy is created by naming the target type as well.
## Return Value
diff --git a/docs/spec/make_proxy_inplace.md b/docs/spec/make_proxy_inplace.md
index 8fd5f3f..eba304e 100644
--- a/docs/spec/make_proxy_inplace.md
+++ b/docs/spec/make_proxy_inplace.md
@@ -14,26 +14,30 @@ proxy make_proxy_inplace(T&& value)
requires(std::is_constructible_v, T>);
// (2)
-template
-proxy make_proxy_inplace(Args&&... args)
+template
+proxy make_proxy_inplace(Args&&... args)
noexcept(std::is_nothrow_constructible_v)
requires(std::is_constructible_v);
// (3)
-template
-proxy make_proxy_inplace(std::initializer_list il, Args&&... args)
+template
+proxy make_proxy_inplace(std::initializer_list il, Args&&... args)
noexcept(std::is_nothrow_constructible_v<
T, std::initializer_list&, Args...>)
requires(std::is_constructible_v&, Args...>);
```
+Let `MP` be the [metadata policy](ProMetadataPolicy.md) of the created `proxy`, which is [`compact_metadata`](compact_metadata.md) for `(1)`.
+
`(1)` Creates a `proxy` object containing a value `p` of type *inplace-ptr<*`std::decay_t`*>*, where `*p` is direct-non-list-initialized with `std::forward(value)`.
-`(2)` Creates a `proxy` object containing a value `p` of type *inplace-ptr<T>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+`(2)` Creates a `proxy` object containing a value `p` of type *inplace-ptr<T>*, where `*p` is direct-non-list-initialized with `std::forward(args)...`.
+
+`(3)` Creates a `proxy` object containing a value `p` of type *inplace-ptr<T>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
-`(3)` Creates a `proxy` object containing a value `p` of type *inplace-ptr<T>*, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`.
+*Since 3.3.0*: For `(1-3)`, if [`inplace_proxiable_target, F, MP>`](inplace_proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
-*Since 3.3.0*: For `(1-3)`, if [`inplace_proxiable_target, F>`](inplace_proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+*Since 5.0.0*: `(2-3)` can name the metadata policy of the created `proxy`. `(1)` deduces the target type, so it always uses the default policy, and a `proxy` with another policy is created by naming the target type as well.
## Return Value
diff --git a/docs/spec/make_proxy_shared.md b/docs/spec/make_proxy_shared.md
index b8c0781..776f46e 100644
--- a/docs/spec/make_proxy_shared.md
+++ b/docs/spec/make_proxy_shared.md
@@ -11,21 +11,25 @@ template
proxy make_proxy_shared(T&& value); // freestanding-deleted
// (2)
-template
-proxy make_proxy_shared(Args&&... args); // freestanding-deleted
+template
+proxy make_proxy_shared(Args&&... args); // freestanding-deleted
// (3)
-template
-proxy make_proxy_shared(std::initializer_list il, Args&&... args); // freestanding-deleted
+template
+proxy make_proxy_shared(std::initializer_list il, Args&&... args); // freestanding-deleted
```
+Let `MP` be the [metadata policy](ProMetadataPolicy.md) of the created `proxy`, which is [`compact_metadata`](compact_metadata.md) for `(1)`.
+
`(1)` Equivalent to `return allocate_proxy_shared>(std::allocator{}, std::forward(value))`.
-`(2)` Equivalent to `return allocate_proxy_shared(std::allocator{}, std::forward(args)...)`.
+`(2)` Equivalent to `return allocate_proxy_shared(std::allocator{}, std::forward(args)...)`.
+
+`(3)` Equivalent to `return allocate_proxy_shared(std::allocator{}, il, std::forward(args)...)`.
-`(3)` Equivalent to `return allocate_proxy_shared(std::allocator{}, il, std::forward(args)...)`.
+*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F, MP>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
-*Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+*Since 5.0.0*: `(2-3)` can name the metadata policy of the created `proxy`. `(1)` deduces the target type, so it always uses the default policy, and a `proxy` with another policy is created by naming the target type as well.
## Return Value
diff --git a/docs/spec/make_proxy_view.md b/docs/spec/make_proxy_view.md
index 102111e..5b6d482 100644
--- a/docs/spec/make_proxy_view.md
+++ b/docs/spec/make_proxy_view.md
@@ -8,11 +8,13 @@
The definition of `make_proxy_view` makes use of an exposition-only class template *observer-ptr*. `observer-ptr` contains a raw pointer to an object of type `T`, and provides `operator*` for access with the same qualifiers.
```cpp
-template
-proxy_view make_proxy_view(T& value) noexcept;
+template
+proxy_view make_proxy_view(T& value) noexcept;
```
-Creates a `proxy_view` object containing a value `p` of type `observer-ptr`, where `p` is direct-non-list-initialized with `std::addressof(value)`. If [`proxiable_target`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+Creates a `proxy_view` object containing a value `p` of type `observer-ptr`, where `p` is direct-non-list-initialized with `std::addressof(value)`. If [`proxiable_target`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated.
+
+*Since 5.0.0*: the [metadata policy](ProMetadataPolicy.md) of the created `proxy_view` can be named explicitly, and defaults to [`compact_metadata`](compact_metadata.md). `make_proxy_view` has a single overload and no target-type parameter, so the policy is named right after the facade.
## Return Value
diff --git a/docs/spec/proxiable.md b/docs/spec/proxiable.md
index 07bcd4c..82c4d6a 100644
--- a/docs/spec/proxiable.md
+++ b/docs/spec/proxiable.md
@@ -5,11 +5,13 @@
> Namespace: `pro::inline v5`
```cpp
-template
+template
concept proxiable = /* see-below */;
```
-The concept `proxiable` specifies that [`proxy`](proxy/README.md) can potentially contain a value of type `P`. If `P` is an incomplete type, the behavior of evaluating `proxiable` is undefined. `proxiable
` is `true` when `F` meets the [*ProFacade* requirements](ProFacade.md) of `P`; otherwise, it is `false`.
+The concept `proxiable
` specifies that [`proxy`](proxy/README.md) can potentially contain a value of type `P`. If `P` is an incomplete type, the behavior of evaluating `proxiable` is undefined. `proxiable
` is `true` when `F` meets the [*ProFacade* requirements](ProFacade.md) of `P` and `MP`; otherwise, it is `false`.
+
+*Since 5.0.0*: `proxiable` takes a [metadata policy](ProMetadataPolicy.md), which participates in the check when a convention of `F` is declared with a [`proxy_dependent_signature`](proxy_dependent_signature.md). `MP` is not itself checked by `proxiable`, and a type that does not meet the *ProMetadataPolicy* requirements is diagnosed where `proxy` is instantiated.
## Example
diff --git a/docs/spec/proxiable_target.md b/docs/spec/proxiable_target.md
index 8582e93..6a295d8 100644
--- a/docs/spec/proxiable_target.md
+++ b/docs/spec/proxiable_target.md
@@ -6,8 +6,9 @@
> Since: 3.3.0
```cpp
-template
-concept proxiable_target = proxiable, observer_facade>;
+template
+concept proxiable_target =
+ proxiable, observer_facade, MP>;
```
See [`make_proxy_view`](make_proxy_view.md) for the definition of the exposition-only class template *observer-ptr*.
diff --git a/docs/spec/proxy/README.md b/docs/spec/proxy/README.md
index 484b119..dc2ed80 100644
--- a/docs/spec/proxy/README.md
+++ b/docs/spec/proxy/README.md
@@ -5,26 +5,29 @@
> Namespace: `pro::inline v5`
```cpp
-template
+template
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)), and offers best-in-class code generation quality, extendibility and accessibility.
-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.
+The [metadata policy](../ProMetadataPolicy.md) `MP` determines how a `proxy` erases an invocation and how it keeps the metadata deduced from the contained type. It governs the size of a `proxy` and the indirections an invocation performs, and it is substituted into any [`proxy_dependent_signature`](../proxy_dependent_signature.md) declared by `F`. It does not otherwise change the behavior of a convention or a reflection. The metadata type depends on `MP`, so a `proxy` converts only to a `proxy` with the same metadata policy. See [`compact_metadata`](../compact_metadata.md) for the metadata policies provided by the library.
+
+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.
Let `Cs` be the convention types of `F` and of every super of `F`, reachable via `typename F::super_types` transitively, and `Rs` be the reflection types of `F` and of every such super.
-- For each distinct dispatch type `D` among the types `C` in `Cs` where `C::is_direct` is `true`, let `Os...` be the overload types of those conventions with duplicates removed, and `substituted-overload-types...` be [`substituted-overload...`](../ProOverload.md). If `D` meets the [*ProAccessible* requirements](../ProAccessible.md) of `proxy, D, substituted-overload-types...`, `typename D::template accessor