fork download
  1. #include <type_traits>
  2. #include <utility>
  3. #include <array>
  4. #include <iostream>
  5.  
  6. // Library //////////////////////////////////////////////
  7.  
  8. // Indexing trick
  9. template <int... Is>
  10. struct seq {};
  11. template <int I, int... Is>
  12. struct gen_seq : gen_seq<I - 1, I - 1, Is...> {};
  13. template <int... Is>
  14. struct gen_seq<0, Is...> : seq<Is...> {};
  15.  
  16. // -- Helpers
  17. namespace {
  18. // Short-cut to get type. Add rvalue-ref if necessary.
  19. template <class T>
  20. typename std::add_rvalue_reference<T>::type val();
  21. // identity operation on types.
  22. template <class T>
  23. struct id { typedef T type; };
  24.  
  25. // Type of a reduction. (To make GCC happy)
  26. template <class F, class Arg, class... Args> struct reduced_type;
  27. template <class F, class Arg> struct reduced_type<F, Arg> : id<Arg> {};
  28. template <class F, class A, class B, class... Args>
  29. struct reduced_type<
  30. F, A, B, Args...> : id<decltype(F()(val<A>(),
  31. val<typename reduced_type<
  32. F, B, Args...>::type>()))> {};
  33.  
  34. // Type list.
  35. template <class... T> struct type_list {};
  36. template <int I, class T, class... Ts>
  37. struct gen_type_list : gen_type_list<I - 1, T, T, Ts...> {};
  38. template <class T, class... Ts>
  39. struct gen_type_list<0, T, Ts...> : type_list<Ts...> {};
  40.  
  41. // Type of an array reduction. (To make GCC happy)
  42. template <class F, class... Args>
  43. typename reduced_type<F, Args...>::type
  44. arr_reduced_type_impl(F, type_list<Args...>);
  45. template <class F, int N, class Arg>
  46. struct arr_reduced_type
  47. : id<decltype(arr_reduced_type_impl(F(), gen_type_list<N, Arg>()))> {};
  48. }
  49.  
  50. // -- Argument reduce
  51. // Reduces an argument list by pair-wise application of `Func` beginning from
  52. // the right hand side.
  53. //
  54. // arg_reduce<Func>()(1, 2, 3) --> f(1, f(2, 3)), where f is Func().
  55. template <class Func>
  56. struct arg_reduce {
  57. // Edge condition: Single argument.
  58. template <class Arg>
  59. constexpr Arg operator()(Arg&& arg) const {
  60. return std::forward<Arg>(arg);
  61. }
  62.  
  63. // Variadic template recursion
  64. template <class Arg, class... Args>
  65. constexpr auto operator()(Arg&& arg, Args&&... args)
  66. const -> typename reduced_type<Func, Arg, Args...>::type {
  67. return Func()(std::forward<Arg>(arg),
  68. operator()(std::forward<Args>(args)...));
  69. }
  70. };
  71.  
  72. // -- Array reduce
  73. // Reduces an array by pair-wise application of `Func` beginning from
  74. // the right hand side.
  75. //
  76. // arr_reduce<Func>()({{1, 2, 3}}) --> f(1, f(2, 3)), where f is Func().
  77. template <class Func>
  78. struct arr_reduce {
  79. private:
  80. // !!! TODO: Is this the correct way of forwarding arrays?
  81. // const ref version
  82. template <class Arg, std::size_t N, int... Is>
  83. constexpr auto arr_reduce_impl(const std::array<Arg, N> &arr, seq<Is...>)
  84. const -> typename arr_reduced_type<Func, N, Arg>::type {
  85. return arg_reduce<Func>()(std::get<Is>(arr)...);
  86. }
  87. // lvalue ref version
  88. template <class Arg, std::size_t N, int... Is>
  89. constexpr auto arr_reduce_impl(std::array<Arg, N> &&arr, seq<Is...>)
  90. const -> typename arr_reduced_type<Func, N, Arg>::type {
  91. return arg_reduce<Func>()(std::get<Is>(std::move(arr))...);
  92. }
  93.  
  94. public:
  95. // const ref interface
  96. template <class Arg, std::size_t N>
  97. constexpr auto operator()(const std::array<Arg, N> &arr)
  98. const -> typename arr_reduced_type<Func, N, Arg>::type {
  99. return arr_reduce_impl(arr, gen_seq<N>{});
  100. }
  101. // lvalue ref interface
  102. template <class Arg, std::size_t N>
  103. constexpr auto operator()(std::array<Arg, N> &&arr)
  104. const -> typename arr_reduced_type<Func, N, Arg>::type {
  105. return arr_reduce_impl(std::move(arr), gen_seq<N>{});
  106. }
  107. };
  108.  
  109. // -- Plus
  110. struct plus {
  111. template <class A, class B>
  112. constexpr auto operator()(A &&a, B &&b)
  113. const -> decltype(std::forward<A>(a) + std::forward<B>(b)) {
  114. return std::forward<A>(a) + std::forward<B>(b);
  115. }
  116. };
  117.  
  118. // -- Multiplies
  119. struct multiplies {
  120. template <class A, class B>
  121. constexpr auto operator()(A &&a, B &&b)
  122. const -> decltype(std::forward<A>(a) * std::forward<B>(b)) {
  123. return std::forward<A>(a) * std::forward<B>(b);
  124. }
  125. };
  126.  
  127. // -- Summation
  128. using arg_sum = arg_reduce<plus>;
  129. using arr_sum = arr_reduce<plus>;
  130. // !!! TODO: Why not?
  131. // arg_sum = arg_reduce<plus>();
  132. // arr_sum = arg_reduce<plus>();
  133.  
  134. // -- Product
  135. using arg_prod = arg_reduce<multiplies>;
  136. using arr_prod = arr_reduce<multiplies>;
  137.  
  138.  
  139. // Test ///////////////////////////////////////////////////
  140.  
  141. int main() {
  142. std::cout << "arg_sum: " << arg_sum()(1) << ", " << arg_sum()(1, 2, 3, 4)
  143. << std::endl;
  144. std::cout << "arr_sum: " << arr_sum()(std::array<int, 1>{ { 1 } }) << ", "
  145. << arr_sum()(std::array<int, 4>{ { 1, 2, 3, 4 } }) << std::endl;
  146. std::cout << "arg_prod: " << arg_prod()(1) << ", "
  147. << arg_prod()(1, 2, 3, 4) << std::endl;
  148. std::cout << "arr_prod: " << arr_prod()(std::array<int, 1>{ { 1 } })
  149. << ", " << arr_prod()(std::array<int, 4>{ { 1, 2, 3, 4 } })
  150. << std::endl;
  151. }
  152.  
Success #stdin #stdout 0s 3340KB
stdin
Standard input is empty
stdout
arg_sum: 1, 10
arr_sum: 1, 10
arg_prod: 1, 24
arr_prod: 1, 24