Conversation
|
An automated preview of the documentation is available at https://113.openmethod.prtest3.cppalliance.org/libs/openmethod/doc/html/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-09-16 14:21:59 UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #113 +/- ##
===========================================
- Coverage 93.51% 93.25% -0.26%
===========================================
Files 22 22
Lines 1695 1706 +11
Branches 504 509 +5
===========================================
+ Hits 1585 1591 +6
- Misses 66 71 +5
Partials 44 44
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
jll63
force-pushed
the
feature/virtual-registry-param
branch
from
September 16, 2026 12:18
ae240ec to
80fce95
Compare
… that follow it Two loose ends from boostorg#96, and one rule for both. `virtual_ptr<C, S>` carries a registry, but the scan that picks a method's registry read the *class's* declared affinity instead of what the parameter carried. `BOOST_OPENMETHOD(f, (virtual_ptr<B, a_registry>), void)` was therefore an error: the scan took `default_registry` from `B`, then rejected the parameter for carrying `a_registry`. And `virtual_<T>` could not name a registry at all. `virtual_` now takes one - `virtual_<T, S>` - declared in `preamble.hpp` and defaulted in `core.hpp`, where the affinity is known; C++ merges default template arguments across declarations. Every virtual parameter then either *carries* a registry or *adopts* the method's: virtual_<T> the class's declared affinity; adopts if it declares none virtual_<T, S> S virtual_ptr<C> C's affinity, else default_registry virtual_ptr<C, S> S `virtual_ptr` never adopts - it is a type in its own right and names a registry whether or not the class declares an affinity. `virtual_` can, because it appears only in a method signature, and that is what lets a method mix a class that has an affinity with one that has not. A method that names a registry requires every carrier to carry it; the adopters go along. A method that names none requires the carriers to agree, and takes their registry. So `method<foo, void(virtual_<A&, default_registry>)>` is `method<foo, void(virtual_<A&, default_registry>), default_registry>`. Nothing that compiles today changes meaning. Two spellings gain one: `virtual_ptr<B, a_registry>` and `virtual_ptr<A, default_registry>` as the sole virtual parameter now decide the method's registry. The sentinel for "carries nothing" is `void`, replacing the `default_affinity` struct - as `inplace_vptr`'s private catch-all spelled it before boostorg#96 unified the hook. It keeps the mangled names short, now that it appears in every `virtual_<T, ...>` of every `method<...>`. `registry_affinity` still maps it to BOOST_OPENMETHOD_DEFAULT_REGISTRY; only `::declared` sees it raw. A member typedef `using boost_openmethod_registry = void;` therefore means "declares nothing". `use_classes` and `BOOST_OPENMETHOD_CLASSES` follow the affinities too, where they used to take the registry from the last element or else the macro default, whatever the classes said - so registering a class that declares an affinity, without naming its registry, put the class in one registry and its methods in another. That was a run-time failure, not a compile error: BOOST_OPENMETHOD_CLASSES(Animal, Dog); // Animal declares zoo_registry BOOST_OPENMETHOD(speak, (virtual_<const Animal&>), std::string); initialize<zoo_registry>(); speak(dog); // before: unknown class Animal, abort; after: "bark" A class list is stricter than a parameter list, because it has no parameter to adopt from and no spelling of its own to disambiguate with. A registry listed last wins, and then a class declaring another one is an error while one declaring nothing goes along. Listing none, the classes must be unanimous - all declaring the same registry, or none declaring one, in which case they are registered into BOOST_OPENMETHOD_DEFAULT_REGISTRY. Mixing a declaring class with a non-declaring one is an error, where the same mixture among a method's parameters is fine. The C++26 reflection registrar keeps the macro default: its groups may name a namespace, whose classes are only known during the scan that the choice of registry feeds. compile_fail_adl_registry_parameter_registry.cpp goes: its premise - that a registry spelled on a parameter contradicts the method - is what this reverses. Two markers move to the fold's new wording. Four compile-fail tests are added, one per new diagnosis, and the carries/adopts table and the six class-list outcomes are pinned with static_asserts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQG6CbE4o2agseE7bDVzHS
jll63
force-pushed
the
feature/virtual-registry-param
branch
from
September 16, 2026 14:18
80fce95 to
80823f5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
(Written by Claude Code, on behalf of @jll63.)
Two loose ends from #96, settled by one rule.
virtual_ptr<C, S>carries a registry, but the scan that picks a method'sregistry read the class's declared affinity instead of what the parameter
carried, so
BOOST_OPENMETHOD(f, (virtual_ptr<B, a_registry>), void)was anerror: the scan took
default_registryfromB, then rejected the parameterfor carrying
a_registry. Andvirtual_<T>could not name a registry at all.Every virtual parameter carries a registry, or adopts
virtual_takes a registry parameter — declared inpreamble.hpp, defaulted incore.hppwhere the affinity is known, since C++ merges default templatearguments across declarations.
virtual_<T>virtual_<T, S>Svirtual_ptr<C>C's affinity, elsedefault_registryvirtual_ptr<C, S>Svirtual_ptrnever adopts — it is a type in its own right and names a registrywhether or not its class declares an affinity.
virtual_can, because itappears only in a method signature, and that is what lets a method mix a class
that has an affinity with one that has not.
A method that names a registry requires every carrier to carry it, and the
adopters go along. A method that names none requires the carriers to agree, and
takes their registry. So
method<foo, void(virtual_<A&, default_registry>)>ismethod<foo, void(virtual_<A&, default_registry>), default_registry>.With
Adeclaringa_registryandBdeclaring nothing:, a_registry, default_registryvirtual_<A&>a_registryvirtual_<B&>default_registryvirtual_<B&, a_registry>a_registryvirtual_ptr<A>a_registryvirtual_ptr<B>default_registryvirtual_ptr<B, a_registry>a_registry(was an error)virtual_ptr<A, default_registry>default_registry(was an error)Nothing that compiles today changes meaning; the two marked rows gain one.
The sentinel for "carries nothing" is
void, replacing thedefault_affinitystruct — as
inplace_vptr's private catch-all spelled it before #96 unified thehook. It keeps the mangled names short, now that it appears in every
virtual_<T, …>of everymethod<…>.registry_affinitystill maps it toBOOST_OPENMETHOD_DEFAULT_REGISTRY; only::declaredsees it raw. A membertypedef
using boost_openmethod_registry = void;therefore means "declaresnothing".
Class lists follow the affinities too
use_classestook the registry from the last element, or else the macrodefault, whatever the classes said — so registering a class that declares an
affinity, without naming its registry, put the class in one registry and its
methods in another. Not a compile error, a crash:
A class list is stricter than a parameter list, because it has no parameter to
adopt from and no spelling of its own to disambiguate with:
use_classes<A, A1>a_registry—A1inherits the declarationuse_classes<B>default_registryuse_classes<A, A1, B, a_registry>a_registry—Bdeclares nothing, so it goes alonguse_classes<A, B>use_classes<A>a_registry(wasdefault_registry, silently)use_classes<A, default_registry>Mixing a declaring class with a non-declaring one is an error, where the same
mixture among a method's parameters is fine. The C++26 reflection registrar
keeps the macro default: its groups may name a namespace, whose classes are
only known during the scan that the choice of registry feeds.
Tests
compile_fail_adl_registry_parameter_registry.cppis removed — its premise,that a registry spelled on a parameter contradicts the method, is what this
reverses. Two markers move to the fold's new wording. Four compile-fail tests
are added, one per new diagnosis, and the carries/adopts table and the six
class-list outcomes above are pinned with
static_asserts.189/189 under gcc 13.3 Debug with warnings as errors, 195/195 under gcc 16 with
C++26 reflection and
BUILD_SHARED_LIBS=ON, and every compile-fail diagnosticwas matched under clang 18.1 as well.
🤖 Generated with Claude Code
https://claude.ai/code/session_01RQG6CbE4o2agseE7bDVzHS