Boost logo

Boost :

From: Jean-Louis Leroy (jl_at_[hidden])
Date: 2025-05-03 20:22:02


> 1. I've tried playing with custom RTTI, because that's what the clang AST
> API uses. When implementing boost_openmethod_vptr, I used
> default_policy::static_vptr<T>. But that seems to defeat the purpose of
> policies and scoping - is there a way to obtain the policy that invoked
> boost_openmethod_vptr?

Ah, good point. I'm going to look into this. Since we cannot specialize function
templates, I'll probably have to pass a Policy& as a parameter.

Logically, with_vptr should usable several times in the same hierarchy, adding
several vptrs to the objects. It makes sense, because external vptrs already
permit associating several vpts to the same object.

Can you share your code? My first idea would be a clang policy. I guess that you
put a switch in boost_openmethod_vptr?

> 2. It sounds strange to me that policies have two functions: a. they behave
> behavior (e.g. what to do in case of error) and b. they act as a type
> registry. That confused me a lot, because in other libraries I got the
> impression that policies only do a. Is there anything preventing the
> separation of concerns here?

In general, policies can have (static) state. For example,
vectored_error_handler contains a static std::function. Each policy that uses it
needs its own. That's the reason for all the CRTPing, and why `fork` rebinds the
first template argument of all the templatized facets to the new policy.

All the methods in the same policy count, at dispatch time, on data created by
initialize<Policy>(). That is why methods have to be scoped in the policy. The
same holds for class registrars: the type_ids they store at static construction
time are not necessarily the same thing in different policies.

> 3. Some of the complexity with policies (like needing a fork function) seem
> to be stemming from the point above. What do you think? For instance,
> couldn't facets be made regular members? Then add/fork can be implementing
> by just inheriting from a base policy, using regular C++.

Do you mean static or instance members? If it is the latter, then policies would
become objects. Which we can pass as template parameters, but it would run into
difficulties, because we don't have universal template parameters yet. A simple
example: use_classes. It uses std::is_base_of to detect if the last class is a
policy. So a policy has got to be a type (unless we change the contracts a lot).

If you mean static members, we are back to the problem of separating my_policy's
error stream from your_policy's.

Policies and facets are definitely advanced stuff. I expect that, over time, we
will have a header with a clang policy, one with a Unity RTTI policy, etc. In a
team or an org, the local expert will create a policy specific to their need -
say, a minimal policy suitable for embedded programming, without any form of
RTTI (using only final constructs), hashing, diagnostic output, etc. It will be
installed as the default policy via BOOST_OPENMETHOD_DEFAULT_POLICY, something
that brings us very close to ODR violations, and requires expertise.

Also, I would expect library authors who use OpenMethod as an implementation
detail, to use their own private policy.

> 4. I had the same impression as Joaquin that virtual_ should be used to
> mark virtual arguments in method definitions, and virtual_ptr and regular
> references in overriders. What do you think?

So, to make sure that we are on the same page, you mean:

    BOOST_OPENMETHOD(poke, (std::ostream &, virtual_<Animal>), void);

    BOOST_OPENMETHOD_OVERRIDE(
        poke, (std::ostream & os, virtual_ptr<Cat> cat), void) { ... }

The problem with this: BOOST_OPENMETHOD would need to foresee what the overrides
will look like. It could be:

    BOOST_OPENMETHOD_OVERRIDE(
        poke, (std::ostream & os, Cat& cat), void) { ... }

...when using with_vptr. Or if the user doesn't need the best performance, maybe
the body of the overriders does enough work to make the cost of the extra
instructions irrelevant.

A secondary benefit: with virtual_ptr in both declarations and overriders, it is
easier to explain the (basic) rules. If you look at YOMM2's doc or my talks, I
often talk about "peeling off" the "virtual_ decorators". With virtual_ptr at
all levels, it is more straightforward to explain.

Finally, it is (a bit) closer to the N2216 syntax.

5. I got the impression that virtual_ptr can't be used with custom RTTI. Is
that true?

No it's not, that would be very disappointing ;-)

virtual_ptr obtains the vptr from the policy, which is the second template
parameter with the default value BOOST_OPENMETHOD_DEFAULT_POLICY.

J-L


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk