I think that this will be quite possible to do with the help of reflections. Seeing the Herb Sutter talk they mention the "instrumentation application" where you essentially takes all the functions from one class, expose them in another class but with added logic around each function. So a more powerful way to achieve what you want seems to be on the way already.
On Wed, Jan 22, 2025 at 10:48 AM Federico Kircheis via Std-Proposals <std-proposals@lists.isocpp.org> wrote:On 22 January 2025 15:29:38 UTC, Dennis Gusev via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
>If you look up "inheriting from STL containers", the top results from SO
>and reddit all mention it being a bad practice since standard containers
>aren't designed to be inherited from.
>
>Specifically, they dont have virtual destructors so there's a risk of UB
>from deleting through pointer to base.
That's not the reason. Even "slicing" isn't the biggest reason. The biggest reason IMO is that "STL types are like a box of chocolates: you never know what you're going to get." The API of a standard library type tends to change in subtle ways with every release, not to mention varying in subtle ways across different vendors. There's no sensible way to "extend" an interface that may change out from under you.
If you think you do know “what you get” when your typeTinherits fromstd::vector: quick, does your typeThave a member function==, and what does it do? Does it haveemplace_back, and if so, what isemplace_back’s return type? Does it have CTAD deduction guides? And so on. It’s not that these questions don’t have answers; it’s that you don’t know the answers (and neither do your coworkers).
[...] If you (or your project, or your company) didn’t writeclass Foo, thenclass Fooshould not be granted control over the API of your own class. And that’s what you’re doing when you inherit from a base class: you’re granting that class control over your API.
What you can safely do is "composition, not inheritance." Take the STL type and make it a member, not a base. Re-expose exactly the API you care about, through an overload set of member functions that you control.Protected and public inheritance.
Are they not enough?
Protected and private inheritance allow you to somewhat-disable the derived-to-base conversion, but:(1) they don't actually take it away, they just make it inaccessible, which can have unwanted effects on overload resolution;(2) they also make-inaccessible all of the member functions, member types, etc., of the base class. My understanding is that Dennis wants to keep the members accessible, so that you can do e.g. `sonOfVector.size()` and `sonOfVector[i]` but forbid `vector<int>(sonOfVector)`.
This goal will feel much more impossible when you realize that C++23's "explicit object parameter" functions allow us to write not onlyvector(const vector& other); // Dennis wants to prevent passing a SonOfVector to that const vector& parameterbut alsosize_t size(this const vector& self); // But Dennis doesn't want to prevent passing a SonOfVector to that const vector& parameter!This is related to the perennial impossibility of "strong typedefs."
–Arthur--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals