Guest User

Curryable functions in C++0x

a guest
Apr 13th, 2010
304
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.37 KB | None | 0 0
  1. #include <tuple>
  2. #include <functional>
  3. #include <memory>
  4. #include <iostream>
  5.  
  6. template<int n>
  7. struct _apply {
  8.   template<typename _Ret, typename... _Fargs, typename... _Targs, typename... _Oargs>
  9.   static _Ret run(std::function<_Ret(_Fargs...)> fn,
  10.                   std::tuple<_Targs...> t,
  11.                   _Oargs... o) {
  12.     return _apply<n-1>::run(fn, t, std::get<n-1>(t), o...);
  13.   }
  14. };
  15.  
  16. template<>
  17. struct _apply<0> {
  18.   template<typename _Ret, typename... _Fargs, typename... _Targs, typename... _Oargs>
  19.   static _Ret run(std::function<_Ret(_Fargs...)> fn,
  20.                   std::tuple<_Targs...> t,
  21.                   _Oargs... o) {
  22.     return fn(o...);
  23.   }
  24. };
  25.  
  26. template<typename _Ret, typename... _Fargs, typename... _Targs, typename... _Oargs>
  27. _Ret apply(std::function<_Ret(_Fargs...)> fn,
  28.            std::tuple<_Targs...> t,
  29.            _Oargs... o) {
  30.   return _apply<sizeof...(_Targs)>::run(fn, t, o...);
  31. }
  32.  
  33.  
  34.  
  35. template<int X, typename A, typename B>
  36. struct __if {
  37.   typedef A result;
  38. };
  39. template<typename A, typename B>
  40. struct __if<0, A, B> {
  41.   typedef B result;
  42. };
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52. template<typename A, typename B> struct _reverse_tuple;
  53.  
  54. template<typename... _Dest>
  55. struct _reverse_tuple<std::tuple<>, std::tuple<_Dest...>> {
  56.   typedef std::tuple<_Dest...> result;
  57. };
  58. template<typename _Orig1, typename... _Orign, typename... _Dest>
  59. struct _reverse_tuple<std::tuple<_Orig1, _Orign...>, std::tuple<_Dest...>> {
  60.   typedef typename _reverse_tuple<std::tuple<_Orign...>, std::tuple<_Orig1, _Dest...>>::result result;
  61. };
  62.  
  63. template<typename... _X>
  64. struct reverse_tuple {
  65.   typedef typename _reverse_tuple<std::tuple<_X...>, std::tuple<>>::result result;
  66. };
  67. template<typename... _X>
  68. struct reverse_tuple<std::tuple<_X...>> {
  69.   typedef typename _reverse_tuple<std::tuple<_X...>, std::tuple<>>::result result;
  70. };
  71.  
  72. template<typename... _X>
  73. struct prepend_tuple;
  74. template<typename... _X, typename _Y>
  75. struct prepend_tuple<std::tuple<_X...>, _Y> {
  76.   typedef std::tuple<_Y, _X...> result;
  77. };
  78.  
  79. template<typename... _X>
  80. struct append_tuple;
  81. template<typename... _X, typename _Y>
  82. struct append_tuple<std::tuple<_X...>, _Y> {
  83. private:
  84.   typedef typename reverse_tuple<_X...>::result reversed;
  85.   typedef typename prepend_tuple<reversed, _Y>::result prepended;
  86. public:
  87.   typedef typename reverse_tuple<prepended>::result result;
  88. };
  89.  
  90. template<typename _X>
  91. struct tuple_maker;
  92. template<typename... _X>
  93. struct tuple_maker<std::tuple<_X...>> {
  94.   static std::tuple<_X...> create(_X... x) {
  95.     return std::tuple<_X...>(x...);
  96.   }
  97.   typedef std::function<std::tuple<_X...>(_X...)> function_type;
  98. };
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105. template<typename _Sig>
  106. class curryable_impl_base;
  107. template<typename _Ret, typename _Arg>
  108. class curryable_impl_base<_Ret(_Arg)> {
  109.  protected:
  110.   typedef _Arg _NextArg;
  111.  public:
  112.   virtual _Ret operator()(_Arg) = 0;
  113. };
  114. template<typename _Ret, typename _Arg, typename... _Args>
  115. class curryable_impl_base<_Ret(_Arg, _Args...)> {
  116.  protected:
  117.   typedef _Arg _NextArg;
  118.  public:
  119.   typedef curryable_impl_base<_Ret(_Args...)> _Next_base;
  120.   virtual std::shared_ptr<_Next_base> operator()(_Arg) = 0;
  121. };
  122.  
  123.  
  124. template<int _N, typename _Si, bool _Zero>
  125. struct _pop_first_n_args;
  126. template<typename _Ret, typename... _Args>
  127. struct _pop_first_n_args<0, _Ret(_Args...), true> {
  128.   typedef _Ret result(_Args...);
  129. };
  130. template<int _N, typename _Ret, typename _Arg, typename... _Args>
  131. struct _pop_first_n_args<_N, _Ret(_Arg, _Args...), false> {
  132.   typedef typename _pop_first_n_args<_N-1, _Ret(_Args...), (_N-1)==0>::result result;
  133. };
  134.  
  135. template<int _N, typename _Sig>
  136. struct pop_first_n_args {
  137.   typedef typename _pop_first_n_args<_N, _Sig, _N==0>::result result;
  138. };
  139.  
  140.  
  141.  
  142.  
  143. template<typename _Sig, typename... _Curried>
  144. class _base_for {
  145. public:
  146.   typedef typename pop_first_n_args<sizeof...(_Curried), _Sig>::result curried_type;
  147.   typedef curryable_impl_base<curried_type> result;
  148. };
  149.  
  150.  
  151.  
  152.  
  153. template<int remaining, typename _Signature, typename _Curried>
  154. class _curryable;
  155.  
  156. template<typename _Ret, typename _Arg, typename... _Args, typename... _Curried>
  157. class _curryable<1, _Ret(_Arg, _Args...), std::tuple<_Curried...>>
  158.   : public _base_for<_Ret(_Arg, _Args...), _Curried...>::result {
  159.     typedef typename _base_for<_Ret(_Arg, _Args...), _Curried...>::result _BaseType;
  160.     typedef std::function<_Ret(_Arg, _Args...)> function_type;
  161.     function_type _fn;
  162.     std::tuple<_Curried...> _items;
  163.  public:
  164.     _curryable(function_type f, std::tuple<_Curried...> i)
  165.       : _fn(f), _items(i) { }
  166.       _Ret operator()(typename _BaseType::_NextArg arg) {
  167.         return apply(_fn, _items, arg);
  168.       }
  169.   };
  170.  
  171. template<int _N, typename _Ret, typename _Arg, typename... _Args, typename... _Curried>
  172. class _curryable<_N, _Ret(_Arg, _Args...), std::tuple<_Curried...>>
  173.   : public _base_for<_Ret(_Arg, _Args...), _Curried...>::result {
  174.     typedef typename _base_for<_Ret(_Arg, _Args...), _Curried...>::result _BaseType;
  175.     typedef typename append_tuple<std::tuple<_Curried...>, typename _BaseType::_NextArg>::result next_tuple_type;
  176.     typedef std::function<_Ret(_Arg, _Args...)> function_type;
  177.     typedef _curryable<_N-1, _Ret(_Arg, _Args...), next_tuple_type> _Next;
  178.     function_type _fn;
  179.     std::tuple<_Curried...> _items;
  180.  public:
  181.     _curryable(function_type f, std::tuple<_Curried...> c)
  182.       : _fn(f), _items(c)
  183.       { }
  184.  
  185.       std::shared_ptr<typename _BaseType::_Next_base>
  186.         operator()(typename _BaseType::_NextArg arg) {
  187.         typedef tuple_maker<next_tuple_type> maker;
  188.         auto new_items(apply(typename maker::function_type(maker::create), _items, arg));
  189.         return std::shared_ptr<_Next>(new _Next(_fn, new_items));
  190.       }
  191.   };
  192.  
  193.  
  194.  
  195.  
  196. template<typename _Sig>
  197. class curryable;
  198.  
  199. template<typename _Ret, typename... _Args>
  200. class curryable<_Ret(_Args...)> {
  201.   typedef std::shared_ptr<curryable_impl_base<_Ret(_Args...)>> impl_type;
  202.   impl_type _impl;
  203.  public:
  204.   curryable(impl_type i) : _impl(i) { }
  205.     curryable(std::function<_Ret(_Args...)> fn)
  206.       : _impl(new _curryable<sizeof...(_Args), _Ret(_Args...), std::tuple<>>(fn, std::tuple<>()))
  207.       { }
  208.  
  209.       typedef typename pop_first_n_args<1, _Ret(_Args...)>::result next_sig;
  210.       typedef typename __if<sizeof...(_Args)-1,  curryable<next_sig>, _Ret>::result next;
  211.       template<typename _Arg>
  212.       next operator()(_Arg arg) {
  213.       return next(_impl->operator()(arg));
  214.     }
  215.  
  216.     template<typename _Arg1, typename... _Argn>
  217.       typename __if<sizeof...(_Args)-1-sizeof...(_Argn),
  218.       curryable<typename pop_first_n_args<1 + sizeof...(_Argn), _Ret(_Args...)>::result>,
  219.       _Ret>::result
  220.       operator()(_Arg1 arg1, _Argn... argn) {
  221.       return operator()(arg1)(argn...);
  222.     }
  223. };
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232. using std::tuple;
  233.  
  234. double apply_test(char const *a, int b, double c) {
  235.   std::cout<<"apply_test(\""<<a<<"\", "<<b<<", "<<c<<");\n";
  236.   return std::string(a).size() + b + c;
  237. }
  238.  
  239. int main() {
  240.   std::function<double(char const *, int, double)> fn1(apply_test);
  241.  
  242.   curryable<double(char const *, int, double)> cc(fn1);
  243.  
  244.   std::cout<<"Calls: "<<cc("1",2,0.1)
  245.            <<"; "<<cc("a")(2)(9.8)
  246.            <<"; "<<cc("e",2)(2)
  247.            <<"; "<<cc("X")(2,3.4)<<"\n";
  248.   std::function<double(double)> partial(cc("foo",2));
  249.   std::cout<<partial(4.5)<<"\n";
  250.  
  251.   curryable<double(char const *,int,double)> fn2(apply_test);
  252.   std::cout<<fn2("4")(8,7.3)<<"\n";
  253.  
  254.   return 0;
  255. }
Advertisement
Add Comment
Please, Sign In to add comment