Skip to content

Commit 77996d8

Browse files
jll63claude
andcommitted
reflection: generalize registration, rename it register_classes
`use_classes_in<^^ns, Registry>` took one namespace and one registry. `register_classes<...>` takes four groups of non-type arguments, each optional, in enforced order - namespaces to scan, classes to register, one `register_classes_opts` value, registries (as reflections now, since the pack is `auto...`) - and registers in every listed registry. Listed classes are dispatch roots: registered whether a method dispatches on them or not, along with the scanned classes deriving from them. Classes with no namespace disable the scan - exactly the listed classes are registered, their inheritance lattice read from reflection and flattened over unlisted intermediates. Scans now skip `boost` as well as `std` - worth ~0.2s per TU on a scan of `^^::` in a Boost.Test TU, and reversible with `scan_boost`/`scan_std`; `no_recurse` keeps a scan out of nested namespaces. The options live in a namespace rather than an enum class so a using-directive can make the terse spellings available. With no namespace and no class at all, the enclosing namespace is scanned. Three routes lead there, all resting on P2996's call-site evaluation of `access_context::current()`: the default template argument covers `register_classes<>`; a `detail::scope_marker` that `BOOST_OPENMETHOD_REGISTER_CLASSES` always prepends covers every macro form, registry-only and options-only included; and the public `current_namespace()` helper covers bare-template argument lists, which the template itself cannot capture - a static_assert points there. The macro no longer pastes `^^`; the caller writes it. The two new compile-fail tests produce the expected diagnostic via `#error` when reflection is off, so they pass under every configuration with no build-file changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UDTJyUvPbFj23o8zVcuvHt
1 parent 427f481 commit 77996d8

46 files changed

Lines changed: 883 additions & 140 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/modules/ROOT/pages/basics.adoc

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ inheritance lattice.
8686
[NOTE]
8787
====
8888
With a compiler that supports C++26 reflection, the class list is unnecessary.
89-
xref:reference:BOOST_OPENMETHOD_CLASSES_IN.adoc[BOOST_OPENMETHOD_CLASSES_IN]
89+
xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[BOOST_OPENMETHOD_REGISTER_CLASSES]
9090
finds the classes on its own - see <<registering_classes_by_reflection>>.
9191
====
9292
@@ -121,7 +121,7 @@ include::{examplesdir}/ast.cpp[tag=content]
121121
122122
When the compiler supports C++26 reflection (P2996), the library can work out
123123
the class list for itself. One call to
124-
xref:reference:BOOST_OPENMETHOD_CLASSES_IN.adoc[BOOST_OPENMETHOD_CLASSES_IN]
124+
xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[BOOST_OPENMETHOD_REGISTER_CLASSES]
125125
replaces every
126126
xref:reference:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] in the
127127
file:
@@ -139,24 +139,38 @@ BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream& os, Dog&), void) {
139139
os << "bark";
140140
}
141141
142-
BOOST_OPENMETHOD_CLASSES_IN(::); // registers all four classes
142+
BOOST_OPENMETHOD_REGISTER_CLASSES(^^::); // registers all four classes
143143
----
144144
145-
The macro scans the namespace it is given - and the namespaces nested in it -
146-
for the methods of the registry. It collects the classes those methods dispatch
147-
on, then registers them, along with every class in the scanned namespaces that
148-
derives from one of them. `Bulldog` above has no overrider of its own and is
149-
named nowhere, and is registered all the same.
150-
151-
A base class that no method dispatches on is *not* registered - it could never
152-
be selected on, and registering it would cost a lattice node, a hash slot and
153-
dispatch table space for nothing. So a hierarchy rooted in some general-purpose
154-
base contributes only the part of itself that takes part in dispatch. As soon as
155-
another method does dispatch on that base, it is registered, and the inheritance
156-
edges through it with it.
157-
158-
Classes declared in the standard library's or the compiler's own headers are not
159-
scanned, so `::` costs little more than the narrower namespace would.
145+
The macro scans the namespaces it is given - and the namespaces nested in them
146+
- for the methods of the registry. It collects the classes those methods
147+
dispatch on, then registers them, along with every class in the scanned
148+
namespaces that derives from one of them. `Bulldog` above has no overrider of
149+
its own and is named nowhere, and is registered all the same.
150+
151+
The arguments come in four groups, each optional, in this order: reflections of
152+
namespaces to scan; reflections of classes to register; one value combining
153+
`register_classes_opts` options with `|`; and reflections of registries to register
154+
the classes in - `boost::openmethod::default_registry` when none is named. A
155+
listed class is registered whether a method dispatches on it or not, along with
156+
the classes the scan finds derive from it. With classes but no namespace,
157+
nothing is scanned: exactly the listed classes are registered, with the
158+
inheritance relations between them read from reflection. With neither -
159+
`BOOST_OPENMETHOD_REGISTER_CLASSES()` - the enclosing namespace is scanned.
160+
161+
A base class that no method dispatches on, and that is not listed, is *not*
162+
registered - it could never be selected on, and registering it would cost a
163+
lattice node, a hash slot and dispatch table space for nothing. So a hierarchy
164+
rooted in some general-purpose base contributes only the part of itself that
165+
takes part in dispatch. As soon as another method does dispatch on that base,
166+
it is registered, and the inheritance edges through it with it.
167+
168+
A scan does not enter the `std` and `boost` namespaces, so `^^::` costs little
169+
more than a narrower namespace would - a method cannot dispatch on a class the
170+
program never heard of anyway. The `register_classes_opts::scan_std` and
171+
`register_classes_opts::scan_boost` options bring them back in; a namespace *listed*
172+
explicitly is always scanned. `register_classes_opts::no_recurse` restricts the scan
173+
to the members declared directly in the listed namespaces.
160174

161175
Reflection sees only what precedes it, so the macro must come *after* the
162176
declarations it is meant to find. Putting it at the bottom of the file is the

doc/modules/ROOT/pages/core_api.adoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,14 @@ We register the classes with `use_classes`:
7878
include::{example}/core_api.cpp[tag=use_classes]
7979
----
8080

81-
With a compiler that supports C++26 reflection, `use_classes_in` replaces that
82-
list. It scans a namespace for the registry's methods, and registers the classes
83-
they dispatch on along with everything in the namespace that derives from them:
81+
With a compiler that supports C++26 reflection, `register_classes` replaces that
82+
list. It scans one or more namespaces for the registry's methods, and registers
83+
the classes they dispatch on along with everything in those namespaces that
84+
derives from them:
8485

8586
[source,c++]
8687
----
87-
BOOST_OPENMETHOD_REGISTER(use_classes_in<^^::>);
88+
BOOST_OPENMETHOD_REGISTER(register_classes<^^::>);
8889
----
8990

9091
A method declared the way `postfix` is above - an alias for a `method`

doc/modules/ROOT/pages/ref_macros.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ uses of the library.
1414
| Adds an overrider to a method.
1515
| xref:reference:BOOST_OPENMETHOD_CLASSES.adoc[*BOOST_OPENMETHOD_CLASSES*]
1616
| Registers classes.
17-
| xref:reference:BOOST_OPENMETHOD_CLASSES_IN.adoc[*BOOST_OPENMETHOD_CLASSES_IN*]
17+
| xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[*BOOST_OPENMETHOD_REGISTER_CLASSES*]
1818
| Registers the classes of a namespace, by reflection.
1919
| xref:reference:BOOST_OPENMETHOD_INLINE_OVERRIDE.adoc[BOOST_OPENMETHOD_INLINE_OVERRIDE]
2020
| Adds an overrider to a method as an inline function.

0 commit comments

Comments
 (0)