#include <iostream>
#include <string>
union any_pointer {
void (*func_ptr)();
void *obj_ptr;
};
template <class FuncPtr, class R>
struct function_ptr_manager {
static R invoke(any_pointer func_ptr)
{
FuncPtr func = reinterpret_cast<FuncPtr>(func_ptr.func_ptr);
return func();
}
};
template <class FuncObj, class R>
struct function_obj_manager {
static R invoke(any_pointer func_obj)
{
FuncObj* func = reinterpret_cast<FuncObj*>(func_obj.obj_ptr);
return (*func)();
}
};
template <class R>
class function {
R (*invoke_)(any_pointer);
any_pointer functor_;
public:
template <class FuncPtr>
void set_function_ptr(FuncPtr func_ptr)
{
invoke_ = &function_ptr_manager<FuncPtr, R>::invoke;
functor_.func_ptr = reinterpret_cast<void(*)()>(func_ptr);
}
template <class FuncObj>
void set_function_obj(FuncObj func_obj)
{
invoke_ = &function_obj_manager<FuncObj, R>::invoke;
functor_.obj_ptr = reinterpret_cast<void*>(new FuncObj(func_obj));
}
R operator()()
{
return invoke_(functor_);
}
};
std::string func() { return "func"; }
struct func_obj { std::string operator()() { return "func_obj"; } };
int main()
{
function<std::string> f;
f.set_function_ptr(func);
std::cout << f() << std::endl;
f.set_function_obj(func_obj());
std::cout << f() << std::endl;
return 0;
}