Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ comment:
# See https://docs.codecov.com/docs/ignoring-paths
ignore:
- extra/**/*
# - test/**/*
# `test/**`, not the sample's `test/**/*`: the latter compiles to
# (?s:test/.*/[^\/]*)\Z, which needs a second slash and so matches only the
# subdirectories of test/ - every top-level test/test_*.cpp stays counted.
# Check a pattern with:
# curl -X POST --data-binary @.codecov.yml https://codecov.io/validate
- test/**
62 changes: 62 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ The library is structured in three conceptual layers:
- Registry and policy framework
- Error types: `not_initialized`, `bad_call`, `no_overrider`, `ambiguous_call`, etc.
- No executable dispatch code
- An internal foundation, *not* an entry point: every other header pulls it in, and
nothing outside `include/` includes it directly. See *Overriding the default registry*
below.

2. **Core API** ([core.hpp](include/boost/openmethod/core.hpp))
- `method<Id, ReturnType(Parameters...), Registry>` - Method implementation
Expand Down Expand Up @@ -330,6 +333,65 @@ One self-contained example per subdirectory of `doc/modules/ROOT/examples/shared
`test/dynamic_loading/` (whose `registry_state_id()` is compared across modules to prove the state
is a single symbol) and `test/implicit_shared_libraries/`.

### Overriding the default registry

The registry is **forward-declared** before `core.hpp` - or any header that includes it,
`<boost/openmethod.hpp>` among them - and **defined after**. Do not reintroduce the old
"include a pre-core header, define the registry, `#define`, then include" idiom:
`preamble.hpp` and `default_registry.hpp` should appear nowhere outside `include/`. Nothing
enforces that automatically; check it by hand when touching this area:

```bash
git grep -n "openmethod/preamble.hpp\|openmethod/default_registry.hpp" -- doc test
```

```cpp
struct my_registry;
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY my_registry

#include <boost/openmethod.hpp>
#include <boost/openmethod/policies/vptr_map.hpp> // extra policies, any order
#include <boost/openmethod/initialize.hpp> // the TU that calls initialize()

struct my_registry
: boost::openmethod::default_registry::with<
boost::openmethod::policies::vptr_map<>> {};
```

A registry the library provides needs no declaration at all - `default_registry`,
`indirect_registry` and the five stock policies are complete as soon as
`<boost/openmethod.hpp>` has been included, because `core.hpp` includes
`default_registry.hpp` *before* it tests the macro:

```cpp
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY boost::openmethod::indirect_registry
#include <boost/openmethod.hpp>
```

This works because every use of the macro in the headers is a name-only context - a default
template argument, an alias, a deduction guide, or a member typedef inside a template. Three
rules:

- The registry must be **complete** before the first construct that instantiates it: a
`BOOST_OPENMETHOD*` macro, `use_classes`, `method`, `virtual_ptr`, `inplace_vptr_base`,
`initialize()`, or `BOOST_OPENMETHOD_{IMPORT,EXPORT,INSTANTIATE}_REGISTRY`. Violating this is
a hard error (`incomplete type ... used in nested name specifier`, from `use_class_aux` in
`core.hpp`) - never silent.
- It must name a **class**, declared with the same class-key (`struct`) as the definition. A
`class`/`struct` mismatch is MSVC C4099, an error under the suite's `/W4 /WX`.
- **Qualify** the name if it could also be found in `namespace boost::openmethod`. The macro
is expanded inside that namespace, so `#define BOOST_OPENMETHOD_DEFAULT_REGISTRY registry`
binds to `boost::openmethod::registry` rather than the global one. That one is loud -
`missing template arguments` - but a name that *does* resolve would bind to the wrong type
silently. `::registry` works.

`test/CMakeLists.txt` withholds the shared PCH from any `test_*.cpp` that overrides the
registry - a force-included PCH would still precede the `#define`. It detects them by scanning
for the token `BOOST_OPENMETHOD_DEFAULT_REGISTRY` **or** for an include of a header that
carries the override on the file's behalf (`test_capture_errors.hpp`). Add another such header
and the scan has to learn about it: miss one and the file still compiles, binds to
`default_registry`, and fails at run time.

### Custom RTTI
When `<typeinfo>` is unavailable or insufficient, use static_rtti or implement custom RTTI. See `doc/modules/ROOT/examples/custom_rtti/` and policies in `include/boost/openmethod/policies/`.

Expand Down
16 changes: 8 additions & 8 deletions doc/modules/ROOT/examples/custom_rtti/1/custom_rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ struct Times : Node {
};
// end::classes[]

// tag::policy[]
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
// tag::setup[]
struct custom_registry;
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
// end::setup[]

// tag::policy[]
struct custom_rtti : boost::openmethod::policies::rtti {
template<class Registry>
struct fn : defaults {
Expand Down Expand Up @@ -75,12 +80,8 @@ struct custom_rtti : boost::openmethod::policies::rtti {
// tag::registry[]
struct custom_registry : boost::openmethod::registry<
custom_rtti, boost::openmethod::policies::vptr_vector> {};

#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
// end::registry[]

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>

using boost::openmethod::virtual_ptr;
Expand Down Expand Up @@ -117,7 +118,6 @@ int main() {
postfix(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::content[]

void call_via_ref(const Node& node, std::ostream& os) {
postfix(node, os);
Expand Down
16 changes: 8 additions & 8 deletions doc/modules/ROOT/examples/custom_rtti/2/custom_rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,15 @@ struct Times : Node {
};
// end::classes[]

// tag::policy[]
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
// tag::setup[]
struct custom_registry;
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
// end::setup[]

// tag::policy[]
// note: vvvvvvvvvvvvvvvv
struct custom_rtti : boost::openmethod::policies::deferred_static_rtti {
template<class Registry>
Expand Down Expand Up @@ -71,12 +76,8 @@ struct custom_rtti : boost::openmethod::policies::deferred_static_rtti {
// tag::registry[]
struct custom_registry : boost::openmethod::registry<
custom_rtti, boost::openmethod::policies::vptr_vector> {};

#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
// end::registry[]

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>

using boost::openmethod::virtual_ptr;
Expand Down Expand Up @@ -111,7 +112,6 @@ int main() {
Plus d{a, b}; Times e{d, c};
std::cout << value(e) << "\n"; // 2 3 + 4 * = 20
}
// end::content[]

auto call_via_ref(const Node& node, std::ostream& os) {
return value(node);
Expand Down
165 changes: 0 additions & 165 deletions doc/modules/ROOT/examples/deferred_custom_rtti.cpp

This file was deleted.

56 changes: 0 additions & 56 deletions doc/modules/ROOT/examples/static_rtti.cpp

This file was deleted.

Loading
Loading