From 31efa6dcc9c3b9c8c46a2a4cde98637979fae892 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Sat, 15 Aug 2026 15:43:48 +0800 Subject: [PATCH] Give each convention a single overload type A convention used to carry a tuple-like overload_types, so adding a convention had to search Cs for an existing convention with the same is_direct and dispatch_type and merge the overload lists into it. That merge is the only reason add_conv_t, merge_conv_t, add_conv_reduction, and conv_specialization_t exist. Replace overload_types with a single overload_type, so add_convention contributes one convention per overload and merging a convention into Cs becomes deduplicating concatenation. Duplicates are still collapsed, so build() is unaffected at both compile time and run time. Accessors still have to be formed per dispatch type, or a dispatch with several overloads would contribute several accessor bases instead of one overload set. Regroup the conventions by dispatch type via conv_group and conv_groups_merge_t just before generating the accessors, which also keeps overload shadowing working. Generalize the reduction helpers to carry extra arguments (reduction_t) and add flattening_merge_t, which merge_tuples_t and conv_groups_merge_t are both expressed in terms of. This changes the ProBasicConvention and ProConvention requirements, so a hand-written convention type must be updated. --- docs/spec/ProBasicConvention.md | 10 +- docs/spec/ProConvention.md | 2 +- .../basic_facade_builder/add_convention.md | 16 +- docs/spec/proxy/README.md | 4 +- docs/spec/proxy/friend_invoke.md | 2 +- docs/spec/proxy_indirect_accessor/README.md | 4 +- .../proxy_indirect_accessor/friend_invoke.md | 2 +- include/proxy/v4/detail/core.h | 323 +++++++++--------- include/proxy/v4/detail/facade_creation.h | 71 ++-- tests/proxy_traits_tests.cpp | 2 +- 10 files changed, 204 insertions(+), 232 deletions(-) diff --git a/docs/spec/ProBasicConvention.md b/docs/spec/ProBasicConvention.md index 1b4dc248..6786e1fc 100644 --- a/docs/spec/ProBasicConvention.md +++ b/docs/spec/ProBasicConvention.md @@ -2,11 +2,11 @@ A type `C` meets the *ProBasicConvention* requirements if the following expressions are well-formed and have the specified semantics. -| Expressions | Semantics | -| ---------------------------- | ------------------------------------------------------------ | -| `C::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the convention applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | -| `typename C::dispatch_type` | A type that defines how the calls are forwarded to the concrete types. Shall be *nothrow-default-constructible* and *nothrow-destructible*. | -| `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md). | +| Expressions | Semantics | +| ------------------------------------------------ | ------------------------------------------------------------ | +| `C::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the convention applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | +| `typename C::dispatch_type` | A type that defines how the calls are forwarded to the concrete types. Shall be *nothrow-default-constructible* and *nothrow-destructible*. | +| `typename C::overload_type`
*(since 5.0.0)* | A type that meets the [*ProOverload* requirements](ProOverload.md). | ## See Also diff --git a/docs/spec/ProConvention.md b/docs/spec/ProConvention.md index 65734671..2d2ac7c3 100644 --- a/docs/spec/ProConvention.md +++ b/docs/spec/ProConvention.md @@ -4,7 +4,7 @@ A type `C` meets the *ProConvention* requirements of a type `P` if `C` meets the | Expressions | Semantics | | ---------------------------- | ------------------------------------------------------------ | -| `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md), and
- when `C::is_direct` is `true`, `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `P` and `O`,
- or otherwise, when `C::is_direct` is `false`, let `QP` be a qualified reference type of `P` with the *cv ref* qualifiers defined by `O` (`QP` is an lvalue reference type if `O` does not define a *ref* qualifier), `qp` be a value of `QP`, `*std::forward(qp)` shall be well-formed, and `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `decltype(*std::forward(qp))` and `O`. | +| `typename C::overload_type` | A type `O` that meets the [*ProOverload* requirements](ProOverload.md), where
- when `C::is_direct` is `true`, `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `P` and `O`,
- or otherwise, when `C::is_direct` is `false`, let `QP` be a qualified reference type of `P` with the *cv ref* qualifiers defined by `O` (`QP` is an lvalue reference type if `O` does not define a *ref* qualifier), `qp` be a value of `QP`, `*std::forward(qp)` shall be well-formed, and `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `decltype(*std::forward(qp))` and `O`. | ## See Also diff --git a/docs/spec/basic_facade_builder/add_convention.md b/docs/spec/basic_facade_builder/add_convention.md index 0797eeca..c432c9d6 100644 --- a/docs/spec/basic_facade_builder/add_convention.md +++ b/docs/spec/basic_facade_builder/add_convention.md @@ -14,18 +14,20 @@ using add_direct_convention = basic_facade_builder; The alias templates `add_convention`, `add_indirect_convention`, and `add_direct_convention` of `basic_facade_builder` add convention types to the template parameters. The expression inside `requires` is equivalent to `sizeof...(Os) > 0u` and each type in `Os` meets the [*ProOverload* requirements](../ProOverload.md). Let `F` be a facade type, - `add_convention` is equivalent to `add_indirect_convention`. -- `add_indirect_convention` merges an implementation-defined convention type `IC` into `Cs`, where: +- `add_indirect_convention` merges an implementation-defined convention type `IC` into `Cs` for each type `O` in `Os`, where: - `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` is `typename D::template accessor, D, `[`substituted-overload`](../ProOverload.md)`...>` if applicable. -- `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs`, where: + - `typename IC::overload_type` is `O`. +- `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs` for each type `O` in `Os`, 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` is `typename D::template accessor, D, `[`substituted-overload`](../ProOverload.md)`...>` if applicable. + - `typename IC::overload_type` is `O`. -When `Cs` already contains a convention type `IC2` where `IC2::is_direct == IC::is_direct && std::is_same_v` is `true`, `Os` merges with `typename IC2::overload_types` and removes duplicates, and `std::tuple_size_v` shall not change. +When `Cs` already contains a convention type identical to `IC`, the template parameters shall not change. + +Let `F` be a facade type. The accessor a convention contributes to a [`proxy`](../proxy/README.md) of `F` is formed per dispatch type rather than per convention: let `Gs` be the types in `Cs` that share `IC::is_direct` and `typename IC::dispatch_type`, and `GOs` be their `overload_type`s in order of first appearance. The accessor is `typename D::template accessor, D, `[`substituted-overload`](../ProOverload.md)`...>` when `IC::is_direct` is `false`, or `typename D::template accessor, D, `[`substituted-overload`](../ProOverload.md)`...>` when it is `true`, if applicable. + +*Since 5.0.0*: each type in `Os` produces its own convention type, rather than one convention type carrying a tuple-like `overload_types`. ## Notes diff --git a/docs/spec/proxy/README.md b/docs/spec/proxy/README.md index 5e56583f..c32fc567 100644 --- a/docs/spec/proxy/README.md +++ b/docs/spec/proxy/README.md @@ -15,9 +15,11 @@ Any instance of `proxy` at any given point in time either *contains a value* 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 `true` and `typename C::dispatch_type` meets the [*ProAccessible* requirements](../ProAccessible.md) of `proxy, typename C::dispatch_type, substituted-overload-types...`, `typename C::dispatch_type::template accessor, typename C::dispatch_type, substituted-overload-types...>` is inherited by `proxy`. Let `Os...` be the element types of `typename C::overload_types`, `substituted-overload-types...` is [`substituted-overload...`](../ProOverload.md). +- 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, D, substituted-overload-types...>` is inherited by `proxy`. - For each type `R` in `Rs`, if `R::is_direct` is `true` and `typename R::reflector_type` meets the [*ProAccessible* requirements](../ProAccessible.md) of `proxy, typename R::reflector_type`, `typename R::reflector_type::template accessor, typename R::reflector_type` is inherited by `proxy`. +*Since 5.0.0*: the accessor of a dispatch type is formed from the overload types of every convention in `Cs` sharing that dispatch type, rather than from a single convention. + ## Member Types | Name | Description | diff --git a/docs/spec/proxy/friend_invoke.md b/docs/spec/proxy/friend_invoke.md index be6fd290..8b8aff89 100644 --- a/docs/spec/proxy/friend_invoke.md +++ b/docs/spec/proxy/friend_invoke.md @@ -21,7 +21,7 @@ There shall be a convention type `Conv` defined in `typename F::convention_types - `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`. +- [`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. diff --git a/docs/spec/proxy_indirect_accessor/README.md b/docs/spec/proxy_indirect_accessor/README.md index fbab8dca..fff00f44 100644 --- a/docs/spec/proxy_indirect_accessor/README.md +++ b/docs/spec/proxy_indirect_accessor/README.md @@ -12,9 +12,11 @@ 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 distinct dispatch type `D` among the types `C` in `Cs` where `C::is_direct` is `false`, 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_indirect_accessor, D, substituted-overload-types...`, `typename D::template accessor, D, substituted-overload-types...>` is inherited by `proxy_indirect_accessor`. - 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`. +*Since 5.0.0*: the accessor of a dispatch type is formed from the overload types of every convention in `Cs` sharing that dispatch type, rather than from a single convention. + ## Member Functions | Name | Description | diff --git a/docs/spec/proxy_indirect_accessor/friend_invoke.md b/docs/spec/proxy_indirect_accessor/friend_invoke.md index 0a5e9f1c..f57877f2 100644 --- a/docs/spec/proxy_indirect_accessor/friend_invoke.md +++ b/docs/spec/proxy_indirect_accessor/friend_invoke.md @@ -21,7 +21,7 @@ There shall be a convention type `Conv` defined in `typename F::convention_types - `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`. +- [`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. diff --git a/include/proxy/v4/detail/core.h b/include/proxy/v4/detail/core.h index 00b87943..0cd9f41f 100644 --- a/include/proxy/v4/detail/core.h +++ b/include/proxy/v4/detail/core.h @@ -77,19 +77,44 @@ struct inapplicable_traits { static constexpr bool applicable = false; }; -template