#include <iostream>
#include <memory>
#include <tuple>
template <class>
struct remove_reference_except_function {};
template <class R, class... Args>
struct remove_reference_except_function<R(&)(Args...)>
{
typedef R(&type)(Args...);
};
template <class R, class... Args>
struct remove_reference_except_function<R(&)(Args......)> //varardic function
{
typedef R(&type)(Args......);
};
//I dont think you can have an rvalue reference to a function? Or can you dereference a non-capturing lambda?
template <class T>
struct remove_reference_except_function<T &>
{
typedef T type;
};
template <class T>
struct remove_reference_except_function<T &&>
{
typedef T type;
};
template< class ReturnType, class... ParamTypes>
struct move_function_base{
virtual ReturnType callFunc(ParamTypes... p) = 0;
};
template<class F, class ReturnType, class... ParamTypes>
class move_function_imp : public move_function_base<ReturnType, ParamTypes...> {
//Using std::remove_reference on a normal function gives you an invalid type for declaring a variable. Hence the custom reference removal
typename remove_reference_except_function<F>::type f_;
public:
virtual ReturnType callFunc(ParamTypes... p) override {
return f_(std::forward<ParamTypes>(p)...);
}
explicit move_function_imp(const typename std::remove_reference<F>::type& f) : f_(f) {}
explicit move_function_imp(typename std::remove_reference<F>::type&& f) : f_(std::move(f)) {}
move_function_imp() = delete;
move_function_imp(const move_function_imp&) = delete;
move_function_imp& operator=(const move_function_imp&) = delete;
};
template<class FuncType>
struct move_function{};
template<class ReturnType, class... ParamTypes>
struct move_function<ReturnType(ParamTypes...)>{
std::unique_ptr<move_function_base<ReturnType,ParamTypes...>> ptr_;
move_function() = default;
template<class F>
move_function(F&& f) :
ptr_(new move_function_imp<F, ReturnType,ParamTypes...>
(std::forward<F>(f))){}
move_function(move_function&& other) = default;
move_function& operator=(move_function&& other) = default;
template<class... Args>
ReturnType
operator()(Args&& ...args)
{
return ptr_->callFunc(std::forward<Args>(args)...);
}
explicit operator bool() const
{
return static_cast<bool>(ptr_);
}
move_function(const move_function&) = delete;
move_function& operator=(const move_function&) = delete;
};
void ff () {std::cout << "Hello World" << std::endl;}
int main()
{
auto f = [](){std::cout << "Hello World" << std::endl;};
auto f2 = move_function<void()>{f};
auto f3 = move_function<void()>{ff}; //Why we need remove_reference_except_function
return 0;
}