Source of Problem https://github.com/claydonkey/PointerToMember/tree/master
Although touched on in How Can I Pass a Member Function to a Function Pointer?, I feel somewhat dissatisfied with the solutions provided, as I don't want to introduce a dependency on the Boost library.
Comparing std::function for member functions is a post that gets close to a solution but ultimately is less optimistic about the use of std::function in . (it seems that member functions cannot be passed as function pointers)
The Problem:
A function simpleFunction
which cannot be altered takes a callback pfunc
:
typedef int (*FuncPtr_t)(void*, std::pair<int,int>&);
static int simpleFunction(FuncPtr_t pfunc, void *context, std::pair<int,int>& nos)
{
pfunc(context, nos);
}
This function is intended to callback the method memberFunction
in class SimpleClass
:
NB removed void from original post as it better represents a real world usage.* was int memberFunction(void*, std::pair<int,int>& nos)
class SimpleClass {
public:
int memberFunction(std::pair<int,int>& nos) { return nos.first + nos.second; }
};
I expected the following to work:
MemFuncPtr_t MemFunction = &SimpleClass::memberFunction;
simpleFunction(obj.*MemFunction, nos);
but obj.*MemFunction
has a type: int (SimpleClass::)(std::pair<int,int>&)
and it needs to be: int (*)(std::pair<int,int>&)
(wheras (obj.*MemFunction) (nos);
returns as expected)
I can create and pass a trampoline:
int functionToMemberFunction(void* context, std::pair<int,int> & nos) {
return static_cast<SimpleClass*>(context)->memberFunction(nos);
}
and pass it
simpleFunction(&functionToMemberFunction, &obj, nos);
but it compiles to around 40 instructions.
I can pass a lambda:
simpleFunction((FuncPtr_t)[](void* , std::pair<int,int> & nos) {
return nos.first + nos.second;
}, &obj, nos);
That's surprisingly well optimised but a bit ugly and syntactically cumbersome. (NB Both and lambdas require C++11)
I can add a static member to SimpleClass
:
class SimpleClass {
public:
int memberFunction(void*, std::pair<int,int>& nos) { return nos.first + nos.second; }
static int staticFunction(void*, std::pair<int,int> & nos) { return nos.first + nos.second; }
};
FuncPtr_t StaticMemFunction = &SimpleClass::staticFunction;
and pass it
simpleFunction(StaticMemFunction, nullptr, nos);
and that's just, well ... a static function inside a class.
I can use the <functional>
header:
using namespace std::placeholders;
std::function<int(std::pair<int,int>&) > f_simpleFunc =
std::bind(&SimpleClass::memberFunction, obj, _1);
auto ptr_fun = f_simpleFunc.target<int (std::pair<int,int> & ) >();
and try and pass it...
simpleFunction(*ptr_fun, nos);
but ptr_fun reports null.
Looking at the x86 assembly - I am at a loss at how memory is addressed, calling a member function (there are an extra 5 instructions [3 mov
, 1 lea
and 1 add
] over the StaticMemFunction
call). I can only imagine that this is down to locating the class instance in memory and then the function within it.