In Bjarne Stroustrup's home page (C++11 FAQ):
struct X { int foo(int); };
std::function<int(X*, int)> f;
f = &X::foo; //pointer to member
X x;
int v = f(&x, 5); //call X::foo() for x with 5
How does it work? How does std::function call a foo member function?
The template parameter is int(X*, int)
, is &X::foo
converted from the member function pointer to a non-member function pointer?!
(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))
To clarify: I know that we don't need to cast any pointer to use std::function, but I don't know how the internals of std::function handle this incompatibility between a member function pointer and a non-member function pointer. I don't know how the standard allows us to implement something like std::function!
After getting help from other answers and comments, and reading GCC source code and C++11 standard, I found that it is possible to parse a function type (its return type and its argument types) by using partial template specialization and function overloading.
The following is a simple (and incomplete) example to implement something like std::function
:
template<class T> class Function { };
// Parse the function type
template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> {
union Pointers {
Res (*func)(Obj*, ArgTypes...);
Res (Obj::*mem_func)(ArgTypes...);
};
typedef Res Callback(Pointers&, Obj&, ArgTypes...);
Pointers ptrs;
Callback* callback;
static Res call_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (*ptrs.func)(&obj, args...);
}
static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (obj.*(ptrs.mem_func))(args...);
}
public:
Function() : callback(0) { }
// Parse the function type
Function(Res (*func)(Obj*, ArgTypes...)) {
ptrs.func = func;
callback = &call_func;
}
// Parse the function type
Function(Res (Obj::*mem_func)(ArgTypes...)) {
ptrs.mem_func = mem_func;
callback = &call_mem_func;
}
Function(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
}
Function& operator=(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
return *this;
}
Res operator()(Obj& obj, ArgTypes... args) {
if(callback == 0) throw 0; // throw an exception
return (*callback)(ptrs, obj, args...);
}
};
Usage:
#include <iostream>
struct Funny {
void print(int i) {
std::cout << "void (Funny::*)(int): " << i << std::endl;
}
};
void print(Funny* funny, int i) {
std::cout << "void (*)(Funny*, int): " << i << std::endl;
}
int main(int argc, char** argv) {
Funny funny;
Function<void(Funny*, int)> wmw;
wmw = &Funny::print; // void (Funny::*)(int)
wmw(funny, 10); // void (Funny::*)(int)
wmw = &print; // void (*)(Funny*, int)
wmw(funny, 8); // void (*)(Funny*, int)
return 0;
}