fork(1) download
  1. #include <array>
  2. #include <cassert>
  3. #include <iostream>
  4. #include <functional>
  5. #include <tuple>
  6. #include <type_traits>
  7.  
  8. /* std::invoke (since C++17) */
  9.  
  10. #define RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
  11.  
  12. template <typename F, typename... As>
  13. auto invoke(F &&f, As &&... as)
  14. RETURN(std::forward<F>(f)(std::forward<As>(as)...));
  15.  
  16. template <typename B, typename T, typename D>
  17. auto invoke(T B::*pmv, D &&d) RETURN(std::forward<D>(d).*pmv);
  18.  
  19. template <typename Pmv, typename Ptr>
  20. auto invoke(Pmv pmv, Ptr &&ptr) RETURN((*std::forward<Ptr>(ptr)).*pmv);
  21.  
  22. template <typename B, typename T, typename D, typename... As>
  23. auto invoke(T B::*pmf, D &&d, As &&... as)
  24. RETURN((std::forward<D>(d).*pmf)(std::forward<As>(as)...));
  25.  
  26. template <typename Pmf, typename Ptr, typename... As>
  27. auto invoke(Pmf pmf, Ptr &&ptr, As &&... as)
  28. RETURN(((*std::forward<Ptr>(ptr)).*pmf)(std::forward<As>(as)...));
  29.  
  30. #undef RETURN
  31.  
  32. /* std::apply (since C++17) */
  33.  
  34. template <typename F, typename Args, size_t... Is>
  35. decltype(auto) apply_impl(F &&f, Args &&args, std::index_sequence<Is...>) {
  36. return invoke(std::forward<F>(f), std::get<Is>(std::forward<Args>(args))...);
  37. }
  38.  
  39. template <typename F, typename Args>
  40. decltype(auto) apply(F &&f, Args &&args) {
  41. return apply_impl(
  42. std::forward<F>(f),
  43. std::forward<Args>(args),
  44. std::make_index_sequence<std::tuple_size<std::decay_t<Args>>::value>());
  45. }
  46.  
  47. /* function_arity */
  48.  
  49. template <typename F>
  50. struct function_arity;
  51.  
  52. template <typename R, typename... Args>
  53. struct function_arity<R (Args...)>
  54. : std::integral_constant<std::size_t, sizeof...(Args)> {};
  55.  
  56. template <typename R, typename... Args>
  57. struct function_arity<R (*)(Args...)> : function_arity<R (Args...)> {};
  58.  
  59. template <typename R, typename... Args>
  60. struct function_arity<R (&)(Args...)> : function_arity<R (Args...)> {};
  61.  
  62. template <typename R, typename C, typename... Args>
  63. struct function_arity<R (C::*)(Args...) const> : function_arity<R (Args...)> {};
  64.  
  65. template <typename R, typename C, typename... Args>
  66. struct function_arity<R (C::*)(Args...)> : function_arity<R (Args...)> {};
  67.  
  68. template <typename C>
  69. struct function_arity : function_arity<decltype(&C::operator())> {};
  70.  
  71. /* make_integer_range */
  72.  
  73. template <typename T, typename U, T Begin>
  74. struct make_integer_range_impl;
  75.  
  76. template <typename T, T... Ints, T Begin>
  77. struct make_integer_range_impl<T, std::integer_sequence<T, Ints...>, Begin> {
  78. using type = std::integer_sequence<T, Begin + Ints...>;
  79. };
  80.  
  81. template <class T, T Begin, T End>
  82. using make_integer_range =
  83. typename make_integer_range_impl<T,
  84. std::make_integer_sequence<T, End - Begin>,
  85. Begin>::type;
  86.  
  87. template <std::size_t Begin, std::size_t End>
  88. using make_index_range = make_integer_range<std::size_t, Begin, End>;
  89.  
  90. /* slice */
  91.  
  92. template <std::size_t... Is, std::size_t... Js>
  93. constexpr decltype(auto) slice_impl(std::index_sequence<Is...>,
  94. std::index_sequence<Js...>) {
  95. using array_t = std::array<std::size_t, sizeof...(Is)>;
  96. return std::index_sequence<std::get<Js>(array_t{{Is...}})...>();
  97. }
  98.  
  99. template <std::size_t Begin, std::size_t End, std::size_t... Is>
  100. constexpr decltype(auto) slice(std::index_sequence<Is...> is) {
  101. return slice_impl(is, make_index_range<Begin, End>());
  102. }
  103.  
  104. /* partial_sum */
  105.  
  106. template <typename Is>
  107. struct partial_sum;
  108.  
  109. template <typename Is>
  110. using partial_sum_t = typename partial_sum<Is>::type;
  111.  
  112. template <>
  113. struct partial_sum<std::index_sequence<>> {
  114. using type = std::index_sequence<>;
  115. };
  116.  
  117. template <std::size_t I, std::size_t... Is>
  118. struct partial_sum<std::index_sequence<I, Is...>> {
  119. private:
  120.  
  121. template <typename Js>
  122. struct impl;
  123.  
  124. template <std::size_t... Js>
  125. struct impl<std::index_sequence<Js...>> {
  126. using type = std::index_sequence<I, Js + I...>;
  127. };
  128.  
  129. public:
  130.  
  131. using type = typename impl<partial_sum_t<std::index_sequence<Is...>>>::type;
  132.  
  133. };
  134.  
  135. /* guarded_apply_impl */
  136.  
  137. template <typename R>
  138. struct guarded_invoke_impl {
  139. template <typename F, typename... Args>
  140. decltype(auto) operator()(F &&f, Args &&...args) const {
  141. return invoke(std::forward<F>(f), std::forward<Args>(args)...);
  142. }
  143. };
  144.  
  145. template <>
  146. struct guarded_invoke_impl<void> {
  147. template <typename F, typename... Args>
  148. auto operator()(F &&f, Args &&... args) const {
  149. invoke(std::forward<F>(f), std::forward<Args>(args)...);
  150. return nullptr;
  151. }
  152. };
  153.  
  154. template <typename T>
  155. struct guarded_invoke_impl<T &> {
  156. template <typename F, typename... Args>
  157. auto operator()(F &&f, Args &&...args) const {
  158. return std::ref(invoke(std::forward<F>(f), std::forward<Args>(args)...));
  159. }
  160. };
  161.  
  162. template <typename F, typename... Args>
  163. decltype(auto) guarded_invoke(F &&f, Args &&... args) {
  164. using R = decltype(invoke(std::forward<F>(f), std::forward<Args>(args)...));
  165. return guarded_invoke_impl<R>{}(std::forward<F>(f),
  166. std::forward<Args>(args)...);
  167. }
  168.  
  169. template <typename F, typename Args, size_t... Is>
  170. static decltype(auto) guarded_apply_impl(F &&f,
  171. Args &&args,
  172. std::index_sequence<Is...>) {
  173. return guarded_invoke(std::forward<F>(f),
  174. std::get<Is>(std::forward<Args>(args))...);
  175. }
  176.  
  177. /* call */
  178.  
  179. template <typename Fs>
  180. struct call_t {
  181.  
  182. explicit call_t(Fs &&fs) : fs_(std::move(fs)) {}
  183.  
  184. template <typename... Args>
  185. auto operator()(Args &&... args) const && {
  186. using function_arities = typename get_function_arities<Fs>::type;
  187. auto partial_sum = partial_sum_t<function_arities>{};
  188. auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
  189. auto is = slice<0, std::tuple_size<Fs>{}>(partial_sum);
  190. auto js = slice<1, std::tuple_size<Fs>{} + 1>(partial_sum);
  191. return apply(
  192. impl<decltype(tuple), decltype(is), decltype(js)>{std::move(tuple)},
  193. std::move(fs_));
  194. }
  195.  
  196. private:
  197.  
  198. template <typename T>
  199. struct get_function_arities;
  200.  
  201. template <typename... Gs>
  202. struct get_function_arities<std::tuple<Gs...>> {
  203. using type = std::index_sequence<0, function_arity<std::decay_t<Gs>>{}...>;
  204. };
  205.  
  206. template <typename Args, typename Is, typename Js>
  207. struct impl;
  208.  
  209. template <typename Args, std::size_t... Is, std::size_t... Js>
  210. struct impl<Args, std::index_sequence<Is...>, std::index_sequence<Js...>> {
  211.  
  212. template <typename... Gs>
  213. auto operator()(Gs &&... gs) const {
  214. using tuple_t = decltype(
  215. std::make_tuple(guarded_apply_impl(std::forward<Gs>(gs),
  216. std::move(args_),
  217. make_index_range<Is, Js>{})...));
  218. // The use of braced-initializer syntax rather than `make_tuple` is
  219. // necessary to guarantee left-to-right order of evaluation.
  220. return tuple_t{guarded_apply_impl(std::forward<Gs>(gs),
  221. std::move(args_),
  222. make_index_range<Is, Js>{})...};
  223. }
  224.  
  225. Args args_;
  226.  
  227. }; // impl
  228.  
  229. Fs fs_;
  230.  
  231. }; // call_t
  232.  
  233. template <typename... Fs>
  234. auto call(Fs &&... fs) {
  235. auto tuple = std::forward_as_tuple(std::forward<Fs>(fs)...);
  236. return call_t<decltype(tuple)>{std::move(tuple)};
  237. }
  238.  
  239. void E() { std::cout << "E()" << std::endl; }
  240.  
  241. int F(int x, int y) {
  242. std::cout << "F(" << x << ", " << y << ')' << std::endl;
  243. return 101;
  244. }
  245.  
  246. int &G(int &x) {
  247. std::cout << "G(" << x << ')' << std::endl;
  248. return x;
  249. }
  250.  
  251. int main() {
  252. {
  253. int n = 42;
  254. auto result = call(E, F, G)(1, 2, n);
  255. assert(result == std::make_tuple(nullptr, 101, 42));
  256. }
  257. {
  258. auto e = []() { std::cout << "e()" << std::endl; };
  259. auto f = [](int x, int y) {
  260. std::cout << "f(" << x << ", " << y << ')' << std::endl;
  261. return 101;
  262. };
  263. auto g = [](int &x) -> int & {
  264. std::cout << "g(" << x << ')' << std::endl;
  265. return x;
  266. };
  267. int n = 42;
  268. auto result = call(e, f, g)(1, 2, n);
  269. assert(result == std::make_tuple(nullptr, 101, 42));
  270. }
  271. }
Success #stdin #stdout 0s 3460KB
stdin
Standard input is empty
stdout
E()
F(1, 2)
G(42)
e()
f(1, 2)
g(42)