#include <iostream>
#include <string>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>
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)();
}
};
struct function_ptr_tag {};
struct function_obj_tag {};
template <class FuncType>
struct get_function_tag {
private:
typedef typename boost::mpl::if_<boost::is_pointer<FuncType>, function_ptr_tag, FuncType>::type func_ptr_tag;
typedef typename boost::mpl::if_<boost::is_same<func_ptr_tag, FuncType>, function_obj_tag, function_ptr_tag>::type ret_type;
public:
typedef ret_type type;
};
template <class R>
class function {
R (*invoke_)(any_pointer);
any_pointer functor_;
public:
template <class FuncType>
function& operator=(FuncType func)
{
typedef typename get_function_tag<FuncType>::type func_tag;
assign_to(func, func_tag());
return *this;
}
R operator()()
{
return invoke_(functor_);
}
private:
template <class FuncPtr>
void assign_to(FuncPtr func_ptr, function_ptr_tag)
{
invoke_ = &function_ptr_manager<FuncPtr, R>::invoke;
functor_.func_ptr = reinterpret_cast<void(*)()>(func_ptr);
}
template <class FuncObj>
void assign_to(FuncObj func_obj, function_obj_tag)
{
invoke_ = &function_obj_manager<FuncObj, R>::invoke;
functor_.obj_ptr = reinterpret_cast<void*>(new FuncObj(func_obj));
}
};
std::string func() { return "func"; }
struct func_obj { std::string operator()() { return "func_obj"; } };
int main()
{
function<std::string> f;
f = &func;
std::cout << f() << std::endl;
f = func_obj();
std::cout << f() << std::endl;
return 0;
}