C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Allow conversion of memfunc pointers to func pointers

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Wed, 17 Jan 2024 13:39:14 +0000
On Wed, Jan 10, 2024 at 2:21 PM Frederick Virchanza Gotham wrote:
>
> Looking at your paper, I've been able to implement the following code of yours:
>
> Derived derived;
> void (Base::*bmfp1)() = &Base::some_virtual_function direct;


I have another idea to implement this. What we want is a 'direct'
member function pointer instead of a 'virtual' member function
pointer. So we do it in three steps as follows:

STEP 1: Get a normal 'virtual' pointer

    void (Base::*bmfp_virtual)() = &Base::some_virtual_function;

STEP 2: Get the VTable pointer for the class whose implementation of
the function you want

    void const *pvtable = typeid(Base).get_polymorphic_facilitator();

STEP 3: Get a 'direct' pointer by passing the result of Step 1 and
Step 2 to 'std::devirtualise'

    void (Base::*bmfp_direct)() = std::devirtualise( bmfp_virtual, pvtable );

So in order to get all of this working, the following two changes
would be required to the standard:

    CHANGE 1: The type 'std::type_info' needs a new consteval static
member function called 'get_polymorphic_facilitator' which returns a
pointer to the class's vtable. (It returns a nullptr is
!std::is_polymorphic_v<T>). The C++ Standard won't need to mention the
word 'vtable', it can just say "polymorphic facilitator" and leave its
implementation as unspecified.

    CHANGE 2: The standard library needs a new standalone constexpr
function called 'std::devirtualise' which changes a 'virtual' pointer
to a 'direct' pointer, which on GNU g++ would be implemented something
like:

    namespace std {
        template<typename R, class Class, typename... Params>
        R (Class::*devirtualise(R (Class::*pmf)(Params...), void const
*const p) noexcept)(Params... args)
        {
            auto n = *static_cast<std::uintptr_t*>(static_cast<void*>(&pmf));
            if ( 0u == (n-- & 1u) ) return pmf; /* no need to devirtualise */
            void const *const *pvtable = static_cast<void const *const
*>(p) - 0x06;
            std::memcpy(&pmf, pvtable + n, sizeof(void(*)(void)));
            return pmf;
        }
    }

GodBolt: https://godbolt.org/z/TfKc7qqbz

Received on 2024-01-17 13:39:28