Hi Lénárd,

 

what about the implementations with different calling convention? (I.e. not using the first parameter as the instance pointer.)

 

Would they create a function stub for those member functions to shift the parameters into the correct register, and memfunc_to_func would return a pointer to that stub instead?
 

-----Ursprüngliche Nachricht-----
Von: Lénárd Szolnoki via Std-Proposals <std-proposals@lists.isocpp.org>
Gesendet: Fr 05.01.2024 19:11
Betreff: Re: [std-proposals] Allow conversion of memfunc pointers to func pointers
An: std-proposals@lists.isocpp.org;
CC: Lénárd Szolnoki <cpp@lenardszolnoki.com>;
Hi,

I think this idea has some merit, and this even has precedent in the form of a GCC extension:

https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html

The GCC extension unfortunately uses C-style cast for the syntax, overloading it with yet another meaning, but featurewise I think it's OK.


On 5 January 2024 13:40:21 CET, Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
>At least 95% of C++ implementations nowadays use a calling convention
>that performs the invocation of a class's member function by moving
>all the arguments down one position, and putting the 'this' pointer in
>the first position.
>
>So for example on x86_64 on Microsoft Windows, if a normal function
>takes three integer arguments, these arguments will be put in RCX,
>RDX, R8. If a member function takes three integer arguments, then
>RCX,RDX,R8 will be moved down to RDX,R8,R9 and then the 'this' pointer
>will be put in RCX.
>
>Only about 4 implementations of C++ leave the function arguments alone
>and store the 'this' pointer in another register (for a list of them,
>see page 4 of http://www.virjacode.com/papers/paper_nrvo_latest.pdf ).

This seems to discuss the calling convention for passing the address of the return slot, not the this parameter.

>
>So anyway, what if we were able to do the following in Standard C++?
>
>    struct Monkey {
>        unsigned i;
>        virtual unsigned Go(double x) { return i +
>static_cast<unsigned>(x + 0.5); }
>    };
>
>    int main(void)
>    {
>        Monkey m = { 8u };
>
>        unsigned (*p)(double) = std::memfunc_to_func( &Monkey::Go, &m );
>
>        std::invoke_func_as_memfunc(p, &m, 45.3);
>    }
>
>The function 'memfunc_to_func' would take two arguments:
>    (1) A pointer to a member function for class T
>    (2) A pointer to an object of type T
>
>It needs the second argument just in case the member function is
>virtual and it needs to look at the vtable of the supplied object.
>
>The function 'invoke_fun_as_memfunc' takes two or more arguments:
>    (1) A normal function pointer which holds the address of a member function
>    (2) An address of an object
>    (3) Any arguments to  be passed to the member function

This looks mostly OK, but there are some things that look off:

1. I think memfunc_to_func should return unsigned (*)(Monkey*, double) in the example above.
2. invoke_func_as_memfunc shouldn't exist, you can just call (or std::invoke) the returned ptr without special treatment.

Cheers,
Lénárd
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals