Date: Mon, 28 Nov 2022 21:34:55 +0100
niedz., 27 lis 2022 o 12:29 Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> napisaĆ(a):
>
> On Sun, Nov 27, 2022 at 2:40 AM Thiago Macieira via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > Think of two base sub-objects in two different classes with different offsets:
> >
> > class wxControl1: public wxTextEdit, public wxControl { ... };
> > class wxControl2: public wxControl, public wxTextEdit { ... };
> >
> > You must either store the actual bases or have a way to restore the offsets
> > from the top-of-object void pointer. That's not static_cast.
> >
> > It can be a dynamic_cast, but not on a void * because the address of the
> > vtable pointer isn't know there either.
>
>
> I have made additions to Darius's code to make it work properly with
> complex cases of virtual inheritance. See here:
>
> https://godbolt.org/z/3qYjhdxxs
>
> Lines 18, 28 and 35 are the lines of interest.
>
> I've copy-pasted the code here:
>
> // BEGIN Chimeric pointer implementation
> #include <type_traits> // is_convertible_v
> #include <tuple> // tuple
>
> // I have chosen to use 'is_convertible_v' instead of "is_base_of_v"
> for two reasons:
> // (1) The latter would accommodate non-public inheritance (we don't want that)
> // (2) Currently the C++ programming language only allows Derived class pointers
> // to be converted to Base class pointers. However in the future, maybe the
> // Standard will be changed to allow some other kind of implicit conversion.
> // I want the chimeric pointer to be versatile and future-proof so I'm
> // choosing 'is_convertible_v' over the alternatives of "is_base_of_v" or
> // 'derived_from'.
>
> template<class... Bases>
> class chimeric_ptr {
> protected:
>
> std::tuple<Bases*...> pointers;
>
If we need 10 bases this class could be bigger than the original object.
Probably a better solution would be to store an offset in some static
memory and add this offset to the `void*` pointer.
Alternative we could store all this offsets in templated function that
will make offsetting for us:
```
template<class BaseA, class BaseB> //dumb down version, possible to do
varaidic but labada will be very complex
class chimeric_ptr
{
std::function<void*(int)> offset; //this could be replaced by
`void*` and pointer to function `void*(void*, int)`
public:
template<typename T>
chimeric_ptr(T* ptr) : offset{ [p = ptr](int i) { switch(i) {
case 0: return (void*)static_cast<BaseA*>(p); case 1: return
(void*)static_cast<BaseB*>(p); } } }
{
}
BaseA* asBaseA() { return (BaseA*)offset(0); }
BaseB* asBaseB() { return (BaseB*)offset(1); }
};
```
I skip all metaprogramming needed to make api look nice and only focus
on very basic functionality, but I hope it is enough to show how it
will work in full version.
Another interesting observation is this `offset` could allow be more
affected by user and permit custom logick, because why need use
`static_cast<BaseA*>` when we could
call member function that return `&p->getMeberRef()` or `&p->member`?
> public:
>
> template<class T>
> requires ((std::is_convertible_v<T*, Bases*> && ...))
> /* implicit */ chimeric_ptr(T *const obj)
> {
> // The fold expression on the next line sets
> // each of the pointers in the tuple
> ((std::get<Bases*>(pointers) = obj), ...);
> }
>
> template<class As>
> requires ((std::is_same_v<Bases, As> || ...))
> As *as(void)
> {
> return std::get<As*>(pointers);
> }
> };
> // END Chimeric pointer implementation
>
> // Example
> struct Control {
> virtual ~Control() = default;
>
> void Refresh();
> void SetBackgroundColour(const char*);
> };
>
> struct TextEntry {
> virtual ~TextEntry() = default;
>
> void SetValue(const char*);
> };
>
> struct TextControl: Control, TextEntry {
> virtual ~TextControl() = default;
> };
>
> struct Combo: Control, TextEntry {
> virtual ~Combo() = default;
> };
>
> void Red( chimeric_ptr<Control,TextEntry> p )
> {
> p.as<Control>()->SetBackgroundColour( "red" );
> p.as<TextEntry>()->SetValue("pending");
> p.as<Control>()->Refresh();
> }
>
> // Invocations
> void UseRed(TextControl* textCtrl, Combo* combo)
> {
> Red(textCtrl);
> Red(combo);
> }
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Std-Proposals <std-proposals_at_[hidden]> napisaĆ(a):
>
> On Sun, Nov 27, 2022 at 2:40 AM Thiago Macieira via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > Think of two base sub-objects in two different classes with different offsets:
> >
> > class wxControl1: public wxTextEdit, public wxControl { ... };
> > class wxControl2: public wxControl, public wxTextEdit { ... };
> >
> > You must either store the actual bases or have a way to restore the offsets
> > from the top-of-object void pointer. That's not static_cast.
> >
> > It can be a dynamic_cast, but not on a void * because the address of the
> > vtable pointer isn't know there either.
>
>
> I have made additions to Darius's code to make it work properly with
> complex cases of virtual inheritance. See here:
>
> https://godbolt.org/z/3qYjhdxxs
>
> Lines 18, 28 and 35 are the lines of interest.
>
> I've copy-pasted the code here:
>
> // BEGIN Chimeric pointer implementation
> #include <type_traits> // is_convertible_v
> #include <tuple> // tuple
>
> // I have chosen to use 'is_convertible_v' instead of "is_base_of_v"
> for two reasons:
> // (1) The latter would accommodate non-public inheritance (we don't want that)
> // (2) Currently the C++ programming language only allows Derived class pointers
> // to be converted to Base class pointers. However in the future, maybe the
> // Standard will be changed to allow some other kind of implicit conversion.
> // I want the chimeric pointer to be versatile and future-proof so I'm
> // choosing 'is_convertible_v' over the alternatives of "is_base_of_v" or
> // 'derived_from'.
>
> template<class... Bases>
> class chimeric_ptr {
> protected:
>
> std::tuple<Bases*...> pointers;
>
If we need 10 bases this class could be bigger than the original object.
Probably a better solution would be to store an offset in some static
memory and add this offset to the `void*` pointer.
Alternative we could store all this offsets in templated function that
will make offsetting for us:
```
template<class BaseA, class BaseB> //dumb down version, possible to do
varaidic but labada will be very complex
class chimeric_ptr
{
std::function<void*(int)> offset; //this could be replaced by
`void*` and pointer to function `void*(void*, int)`
public:
template<typename T>
chimeric_ptr(T* ptr) : offset{ [p = ptr](int i) { switch(i) {
case 0: return (void*)static_cast<BaseA*>(p); case 1: return
(void*)static_cast<BaseB*>(p); } } }
{
}
BaseA* asBaseA() { return (BaseA*)offset(0); }
BaseB* asBaseB() { return (BaseB*)offset(1); }
};
```
I skip all metaprogramming needed to make api look nice and only focus
on very basic functionality, but I hope it is enough to show how it
will work in full version.
Another interesting observation is this `offset` could allow be more
affected by user and permit custom logick, because why need use
`static_cast<BaseA*>` when we could
call member function that return `&p->getMeberRef()` or `&p->member`?
> public:
>
> template<class T>
> requires ((std::is_convertible_v<T*, Bases*> && ...))
> /* implicit */ chimeric_ptr(T *const obj)
> {
> // The fold expression on the next line sets
> // each of the pointers in the tuple
> ((std::get<Bases*>(pointers) = obj), ...);
> }
>
> template<class As>
> requires ((std::is_same_v<Bases, As> || ...))
> As *as(void)
> {
> return std::get<As*>(pointers);
> }
> };
> // END Chimeric pointer implementation
>
> // Example
> struct Control {
> virtual ~Control() = default;
>
> void Refresh();
> void SetBackgroundColour(const char*);
> };
>
> struct TextEntry {
> virtual ~TextEntry() = default;
>
> void SetValue(const char*);
> };
>
> struct TextControl: Control, TextEntry {
> virtual ~TextControl() = default;
> };
>
> struct Combo: Control, TextEntry {
> virtual ~Combo() = default;
> };
>
> void Red( chimeric_ptr<Control,TextEntry> p )
> {
> p.as<Control>()->SetBackgroundColour( "red" );
> p.as<TextEntry>()->SetValue("pending");
> p.as<Control>()->Refresh();
> }
>
> // Invocations
> void UseRed(TextControl* textCtrl, Combo* combo)
> {
> Red(textCtrl);
> Red(combo);
> }
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2022-11-28 20:35:07