Date: Fri, 5 Jan 2024 15:51:52 +0000
On Friday, January 5, 2024, Jason McKesson wrote:
>
>
> The proposal being referenced (which BTW is *different* from the
> proposal that Frederick is pushing) doesn't allow for polymorphism
> with such function pointers.
>
What I'm proposing would allow some really freaky funky behaviour as
follows:
struct Base { virtual int Go(float) { return 5; } };
struct Derived1 : Base { int Go(float) override { return 6; } };
struct Derived2 : Base { int Go(float) override { return 7; } };
Derived1 a;
Derived2 b;
int (*p)(float) = std::memfunc_to_func( &Base::Go, &a);
std::invoke_func_as_memfunc(p, &b, 65.2f);
The above code will invoke the 'Derived2::Go' member function on an object
of type 'Derived1'. I'm not saying that this is what the feature is
designed for -- I'm just showing how it works and what it's capable of.
Specifically here is how 'memfunc_to_func' will work:
(1) If only 1 argument is supplied, then it returns the address of the
implementation of the member function belonging to the class (so if you
give it '&Base::Go' as the 1st argument then you get back the address of
Base's implementation of 'Go').
(2) If 2 arguments are supplied, and if the member function is virtual,
it looks at the second argument's vtable to get the function's address from
the vtable. So if you give it '&Base::Go' as the 1st argument then you
might actually get back the address of Derived1's implementation of 'Go'.
If you only supply one argument to 'memfunc_to_func', and if that one
argument is the address of a member function belonging to an abstract
class, and if the member function is pure virtual (i.e. not implemented),
then you get a nullptr.
If you supply a nullptr to 'std::invoke_func_as_memfunc' then it has no
effect and the behaviour is well-defined.
>
>
> The proposal being referenced (which BTW is *different* from the
> proposal that Frederick is pushing) doesn't allow for polymorphism
> with such function pointers.
>
What I'm proposing would allow some really freaky funky behaviour as
follows:
struct Base { virtual int Go(float) { return 5; } };
struct Derived1 : Base { int Go(float) override { return 6; } };
struct Derived2 : Base { int Go(float) override { return 7; } };
Derived1 a;
Derived2 b;
int (*p)(float) = std::memfunc_to_func( &Base::Go, &a);
std::invoke_func_as_memfunc(p, &b, 65.2f);
The above code will invoke the 'Derived2::Go' member function on an object
of type 'Derived1'. I'm not saying that this is what the feature is
designed for -- I'm just showing how it works and what it's capable of.
Specifically here is how 'memfunc_to_func' will work:
(1) If only 1 argument is supplied, then it returns the address of the
implementation of the member function belonging to the class (so if you
give it '&Base::Go' as the 1st argument then you get back the address of
Base's implementation of 'Go').
(2) If 2 arguments are supplied, and if the member function is virtual,
it looks at the second argument's vtable to get the function's address from
the vtable. So if you give it '&Base::Go' as the 1st argument then you
might actually get back the address of Derived1's implementation of 'Go'.
If you only supply one argument to 'memfunc_to_func', and if that one
argument is the address of a member function belonging to an abstract
class, and if the member function is pure virtual (i.e. not implemented),
then you get a nullptr.
If you supply a nullptr to 'std::invoke_func_as_memfunc' then it has no
effect and the behaviour is well-defined.
Received on 2024-01-05 15:51:55