Thanks for all answers.
I found a good example from section 14.8.2.5-21 of the standard:
template<class> struct X { };
template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };
template<class ... Types> struct Y { };
template<class T, class ... Types> struct Y<T, Types& ...> { };
template<class ... Types> int f(void (*)(Types ...));
void g(int, float);
// uses primary template
X<int> x1;
// uses partial specialization; ArgTypes contains float, double
X<int(int, float, double)> x2;
// uses primary template
X<int(float, int)> x3;
// use primary template; Types is empty
Y<> y1;
// uses partial specialization; T is int&, Types contains float, double
Y<int&, float&, double&> y2;
// uses primary template; Types contains int, float, double
Y<int, float, double> y3;
// OK; Types contains int, float
int fv = f(g);
It says that with template specialization, we can parse template parameters of a function type (awesome)! The following is a dirty/simple example about how std::function can work:
template<class T> struct Function { };
template<class T, class Obj, class... Args>
struct Function<T(Obj*, Args...)> // Parsing the function type
{
enum FuncType
{
FuncTypeFunc,
FuncTypeMemFunc
};
union FuncPtr
{
T(*func)(Obj*, Args...);
T(Obj::*mem_func)(Args...);
};
FuncType m_flag;
FuncPtr m_func_ptr;
Function(T(*func)(Obj*, Args...)) // void(*)(Funny*, int, int)
{
m_flag = FuncTypeFunc;
m_func_ptr.func = func;
}
Function(T(Obj::*mem_func)(Args...)) // void(Funny::*)(int, int)
{
m_flag = FuncTypeMemFunc;
m_func_ptr.mem_func = mem_func;
}
void play(Obj* obj, Args... args)
{
switch(m_flag)
{
case FuncTypeFunc:
(*m_func_ptr.func)(obj, args...);
break;
case FuncTypeMemFunc:
(obj->*m_func_ptr.mem_func)(args...);
break;
}
}
};
Usage:
#include <iostream>
struct Funny
{
void done(int i, int j)
{
std::cout << "Member Function: " << i << ", " << j << std::endl;
}
};
void done(Funny* funny, int i, int j)
{
std::cout << "Function: " << i << ", " << j << std::endl;
}
int main(int argc, char** argv)
{
Funny funny;
Function<void(Funny*, int, int)> f = &Funny::done; // void(Funny::*)(int, int)
Function<void(Funny*, int, int)> g = &done; // void(*)(Funny*, int, int)
f.play(&funny, 5, 10); // void(Funny::*)(int, int)
g.play(&funny, 5, 10); // void(*)(Funny*, int, int)
return 0;
}
Edit: Thanks to Tomek for his good hint about union
s, the above example is changed to hold the member/non-member function pointer in one (not two) variable.
Edit: Martin York is right, the switch statement wasn't a good idea in the above example, so i changed the example completely to work better, the following isn't dirty anymore :-)
template<class T> class Function { };
template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> // Parsing the function type
{
union Pointers // An union to hold different kind of pointers
{
Res (*func)(Obj*, ArgTypes...); // void (*)(Funny*, int)
Res (Obj::*mem_func)(ArgTypes...); // void (Funny::*)(int)
};
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...); // void (*)(Funny*, int)
}
static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args)
{
return (obj.*(ptrs.mem_func))(args...); // void (Funny::*)(int)
}
public:
Function() : callback(0) { }
Function(Res (*func)(Obj*, ArgTypes...)) // void (*)(Funny*, int)
{
ptrs.func = func;
callback = &call_func;
}
Function(Res (Obj::*mem_func)(ArgTypes...)) // void (Funny::*)(int)
{
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;
}