Single-Expression Member Function Pointers

Viewed 78

The standard way to represent a pointer to a member function for a specific instance of a class is to use a pointer to the instance and a pointer to the member function:

void Execute(Foo* inst, void (Foo::*func)(int), int x) {
  (inst->*func)(x);
}
...
Execute(foo, &Foo::Bar, 42);

Is there any way to define Execute such that the function pointer is represented as a single expression?

For example:

void Execute(SomeType v, int x) {
  (v.inst->*v.func)(x);
}
...
Execute(foo->Bar, 42);

My main problem is that in my specific case, Foo is nested under a long and unstable chain of namespaces, so an actual invocation using the standard syntax looks more like Execute(foo, &hello::darkness::my::old::friend::Foo::Bar, 42). I almost always have a local foo instance however, from which I can refer to the much simpler foo->Bar(42). I need to do some extra bookkeeping though, which is why I need to wrap the call in something like Execute. using directives and namespace aliases are not an option unfortunately.

1 Answers

Is there any way to define Execute such that the function pointer is represented as a single expression?

Yes. Change the function to use std::function or a callable template parameter, eg:

#include <functional>

void Execute(std::function<void(int)> v, int x)
{
    v(x);
}
template<typename Callable>
void Execute(Callable v, int x)
{
    v(x);
}

And then you can use std::bind() or a lambda for the input expression, eg:

#include <functional>

using namespace std::placeholders;
using FooType = std::remove_reference<decltype(*foo)>::type;

Execute(std::bind(&FooType::Bar, foo, _1), 42);
// or, in C++20 and later:
Execute(std::bind_front(&FooType::Bar, foo), 42);
Execute([=](int x){ foo->Bar(x); }, 42);

Also, just to mention that in C++Builder specifically, there is a __closure extension that allows calling member methods without having to qualify the class type at all, eg:

typedef void (__closure *TExecuteCallable)(int);

void Execute(TExecuteCallable v, int x)
{
    v(x);
}

...

Execute(foo->Bar, 42);
// or
Execute(&(foo->Bar), 42);
Related