fork download
  1. #include <iostream>
  2. #include <memory>
  3. #include <tuple>
  4.  
  5. template <class>
  6. struct remove_reference_except_function {};
  7.  
  8. template <class R, class... Args>
  9. struct remove_reference_except_function<R(&)(Args...)>
  10. {
  11. typedef R(&type)(Args...);
  12. };
  13.  
  14. template <class R, class... Args>
  15. struct remove_reference_except_function<R(&)(Args......)> //varardic function
  16. {
  17. typedef R(&type)(Args......);
  18. };
  19. //I dont think you can have an rvalue reference to a function? Or can you dereference a non-capturing lambda?
  20. template <class T>
  21. struct remove_reference_except_function<T &>
  22. {
  23. typedef T type;
  24. };
  25.  
  26. template <class T>
  27. struct remove_reference_except_function<T &&>
  28. {
  29. typedef T type;
  30. };
  31.  
  32. template< class ReturnType, class... ParamTypes>
  33. struct move_function_base{
  34. virtual ReturnType callFunc(ParamTypes... p) = 0;
  35. };
  36.  
  37. template<class F, class ReturnType, class... ParamTypes>
  38. class move_function_imp : public move_function_base<ReturnType, ParamTypes...> {
  39.  
  40. //Using std::remove_reference on a normal function gives you an invalid type for declaring a variable. Hence the custom reference removal
  41. typename remove_reference_except_function<F>::type f_;
  42.  
  43. public:
  44. virtual ReturnType callFunc(ParamTypes... p) override {
  45. return f_(std::forward<ParamTypes>(p)...);
  46. }
  47. explicit move_function_imp(const typename std::remove_reference<F>::type& f) : f_(f) {}
  48. explicit move_function_imp(typename std::remove_reference<F>::type&& f) : f_(std::move(f)) {}
  49.  
  50. move_function_imp() = delete;
  51. move_function_imp(const move_function_imp&) = delete;
  52. move_function_imp& operator=(const move_function_imp&) = delete;
  53. };
  54.  
  55.  
  56. template<class FuncType>
  57. struct move_function{};
  58.  
  59. template<class ReturnType, class... ParamTypes>
  60. struct move_function<ReturnType(ParamTypes...)>{
  61. std::unique_ptr<move_function_base<ReturnType,ParamTypes...>> ptr_;
  62.  
  63. move_function() = default;
  64. template<class F>
  65. move_function(F&& f) :
  66. ptr_(new move_function_imp<F, ReturnType,ParamTypes...>
  67. (std::forward<F>(f))){}
  68. move_function(move_function&& other) = default;
  69. move_function& operator=(move_function&& other) = default;
  70.  
  71. template<class... Args>
  72. ReturnType
  73. operator()(Args&& ...args)
  74. {
  75. return ptr_->callFunc(std::forward<Args>(args)...);
  76. }
  77.  
  78. explicit operator bool() const
  79. {
  80. return static_cast<bool>(ptr_);
  81. }
  82.  
  83. move_function(const move_function&) = delete;
  84. move_function& operator=(const move_function&) = delete;
  85. };
  86. void ff () {std::cout << "Hello World" << std::endl;}
  87. int main()
  88. {
  89. auto f = [](){std::cout << "Hello World" << std::endl;};
  90. auto f2 = move_function<void()>{f};
  91. auto f3 = move_function<void()>{ff}; //Why we need remove_reference_except_function
  92. return 0;
  93. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
Standard output is empty