C++ Logo

std-proposals

Advanced search

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

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Fri, 05 Jan 2024 19:11:18 +0100
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_at_[hidden]> 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

Received on 2024-01-05 18:11:26