fork download
  1. #include <utility>
  2. #include <iostream>
  3. #include <memory>
  4.  
  5.  
  6. template<class T>
  7. struct moved_value{
  8. moved_value(T* v):pval(v){};
  9.  
  10. T& get(){return *pval;}
  11. const T& get()const{return *pval;}
  12.  
  13. private:
  14. T* pval;
  15.  
  16. };
  17. // Copied with removal of Parameter info from
  18. // http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda
  19.  
  20.  
  21. template <typename T>
  22. struct function_traits
  23. : public function_traits<decltype(&T::operator())>
  24. {};
  25. // For generic types, directly use the result of the signature of its 'operator()'
  26.  
  27. template <typename ClassType, typename ReturnType, typename... Args>
  28. struct function_traits<ReturnType(ClassType::*)(Args...) const>
  29. // we specialize for pointers to member function
  30. {
  31. typedef ReturnType result_type;
  32.  
  33. };
  34.  
  35. template<class T,class F>
  36. struct move_lambda{
  37. T val;
  38. F f_;
  39.  
  40. typedef function_traits<F> traits;
  41. typedef typename traits::result_type result_type;
  42.  
  43.  
  44.  
  45. move_lambda(T&& v, F f):val(std::move(v)),f_(f){};
  46. move_lambda(move_lambda&& other):val(std::move(other.val)),f_(std::move(other.f_)){}
  47.  
  48. move_lambda& operator=(move_lambda&& other){
  49. val = std::move(other.val);
  50. f_ = std::move(other.f_);
  51.  
  52. }
  53.  
  54. template<class... Args>
  55. auto operator()(Args&& ...args) -> result_type
  56. {
  57. moved_value<T> mv(&val);
  58. return f_(mv,std::forward<Args>(args)...);
  59.  
  60. }
  61.  
  62.  
  63.  
  64. private:
  65. move_lambda();
  66. move_lambda(const move_lambda&);
  67. move_lambda& operator=(const move_lambda&);
  68.  
  69.  
  70.  
  71.  
  72. };
  73.  
  74. template<class T,class F>
  75. move_lambda<T,F>create_move_lambda(T&& t, F f){
  76. return move_lambda<T,F>(std::move(t),f);
  77. }
  78.  
  79. // Unfortunately, std::function does not seem to support move-only callables
  80. // Here is our quick movable replacement
  81. template< class ReturnType, class... ParamTypes>
  82. struct movable_function_base{
  83. virtual ReturnType callFunc(ParamTypes&&... p) = 0;
  84.  
  85. };
  86.  
  87.  
  88. template<class F, class ReturnType, class... ParamTypes>
  89. struct movable_function_imp:public movable_function_base<ReturnType,ParamTypes...>{
  90. F f_;
  91. virtual ReturnType callFunc(ParamTypes&&... p){
  92. return f_(std::forward<ParamTypes>(p)...);
  93. }
  94.  
  95. explicit movable_function_imp(F&& f):f_(std::move(f)){};
  96.  
  97.  
  98.  
  99. private:
  100. movable_function_imp();
  101. movable_function_imp(const movable_function_imp&);
  102. movable_function_imp& operator=(const movable_function_imp&);
  103. };
  104.  
  105.  
  106. template<class FuncType>
  107. struct movable_function{};
  108.  
  109. template<class ReturnType, class... ParamTypes>
  110. struct movable_function<ReturnType(ParamTypes...)>{
  111. std::unique_ptr<movable_function_base<ReturnType,ParamTypes...>> ptr_;
  112.  
  113. template<class F>
  114. explicit movable_function(F&& f):ptr_(new movable_function_imp<F,ReturnType,ParamTypes...>(std::move(f))){}
  115. movable_function(movable_function&& other):ptr_(std::move(other.ptr_)){}
  116. movable_function& operator=(movable_function&& other){
  117. ptr_ = std::move(other.ptr_);
  118. return *this;
  119. }
  120.  
  121. template<class... Args>
  122. auto operator()(Args&& ...args) -> ReturnType
  123. {
  124. return ptr_->callFunc(std::forward<Args>(args)...);
  125.  
  126. }
  127. private:
  128. movable_function();
  129. movable_function(const movable_function&);
  130. movable_function& operator=(const movable_function&);
  131.  
  132. };
  133.  
  134.  
  135.  
  136.  
  137. struct TestMove{
  138. TestMove():k(0){}
  139. TestMove(TestMove&& other):k(other.k){
  140. other.k = -1;
  141. }
  142. TestMove& operator=(TestMove&& other){
  143. k = other.k;
  144. other.k = -1;
  145. return *this;
  146. }
  147.  
  148. int k;
  149. private:
  150. TestMove(const TestMove&);
  151. TestMove& operator=(const TestMove&);
  152.  
  153.  
  154. };
  155.  
  156. movable_function<void()> CreateLambda()
  157.  
  158. {
  159. typedef TestMove HugeObject;
  160. HugeObject hugeObj;
  161. hugeObj.k = 9;
  162.  
  163. // ...preparation of hugeObj...
  164.  
  165.  
  166. auto f = create_move_lambda(std::move(hugeObj),[](moved_value<HugeObject> hugeObj){// manipulate huge object
  167. std::cout << hugeObj.get().k << std::endl;
  168.  
  169. });
  170.  
  171. movable_function<void()> toReturn(std::move(f));
  172.  
  173. return toReturn;
  174.  
  175. }
  176.  
  177.  
  178. int main(){
  179.  
  180. // A movable only type, not copyable
  181. TestMove m;
  182. m.k = 5;
  183.  
  184. // A movable only type, not copyable
  185. TestMove m2;
  186. m2.k = 6;
  187.  
  188. // Create a lambda that takes 2 parameters and returns int
  189. auto lambda = create_move_lambda(std::move(m),[](moved_value<TestMove> m,int i,int)->int{std::cout << m.get().k << " " << i << std::endl;return 7;});
  190.  
  191. // Create a lambda that takes 0 parameters and returns void
  192. auto lambda2 = create_move_lambda(std::move(m2),[](moved_value<TestMove> m){std::cout << m.get().k << std::endl;});
  193.  
  194.  
  195. std::cout << lambda(1,2) << std::endl;
  196.  
  197. lambda2();
  198.  
  199.  
  200.  
  201.  
  202. // Compiler error if you try to copy
  203. //auto lambda4 = lambda;
  204.  
  205. // Able to move
  206. auto lambda3 = std::move(lambda2);
  207. lambda3();
  208.  
  209. auto lambda4 = CreateLambda();
  210.  
  211. lambda4();
  212.  
  213. }
  214.  
Success #stdin #stdout 0s 3060KB
stdin
Standard input is empty
stdout
5 1
7
6
6
9