fork(3) download
  1. #include <iostream>
  2. #include <tuple>
  3. #include <functional>
  4. #include <string>
  5. #include <sstream>
  6. using namespace std;
  7.  
  8. /**************************
  9.  * Filler code.....
  10.  * ************************/
  11.  
  12. template <typename T>
  13. struct Rand;
  14. template <>
  15. struct Rand<int> { static inline int get(int i) { return 100 + i; } };
  16. template <>
  17. struct Rand<std::string>
  18. {
  19. static inline std::string get(int i)
  20. {
  21. std::stringstream ss;
  22. ss << "Text (" << i << ")";
  23. return ss.str();
  24. }
  25. };
  26. template <>
  27. struct Rand<double> { static inline double get(int i) { return (float)i + 0.001; } };
  28.  
  29. /**************************
  30.  * Generic helper TMP stuff
  31.  * ************************/
  32.  
  33. template <size_t...>
  34. struct index_sequence {};
  35.  
  36. template <size_t Int1, size_t... Intn>
  37. struct index_sequence_generator : index_sequence_generator<Int1-1, Int1-1, Intn...>{};
  38. template <size_t... Intn>
  39. struct index_sequence_generator<0, Intn...>
  40. {
  41. typedef index_sequence<Intn...> type;
  42. };
  43. template <size_t N>
  44. using make_index_sequence = typename index_sequence_generator<N>::type;
  45. template <typename... Args>
  46. using index_sequence_for = make_index_sequence<sizeof...(Args)>;
  47.  
  48. template<typename...>
  49. struct type_sequence {};
  50.  
  51. template <typename T>
  52. class has_operator_func
  53. {
  54. template <typename C> static char test( decltype(&C::operator()) ) ;
  55. template <typename C> static long test(...);
  56. public:
  57. enum { value = sizeof(test<T>(0)) == sizeof(char) };
  58. };
  59.  
  60. template <typename T>
  61. struct function_type_forced
  62. {
  63. static_assert(has_operator_func<T>::value,
  64. "function_traits may only act on objects with operator() or defined functions");
  65. typedef decltype(&T::operator()) type;
  66. };
  67. template <typename T>
  68. using force_function_type = typename function_type_forced<T>::type;
  69.  
  70. template <typename T>
  71. struct function_traits : public function_traits<force_function_type<T>> {};
  72. template <typename R, typename... Args>
  73. struct function_traits_base
  74. {
  75. typedef R result_type;
  76.  
  77. enum { arg_num = sizeof...(Args) };
  78. template <size_t i>
  79. struct arg
  80. {
  81. typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
  82. };
  83. typedef type_sequence<Args...> arg_types;
  84. };
  85. template <typename C, typename R, typename... Args>
  86. struct function_traits<R(C::*)(Args...) const> : public function_traits_base<R, Args...> {};
  87. template <typename C, typename R, typename... Args>
  88. struct function_traits<R(C::*)(Args...)> : public function_traits_base<R, Args...> {};
  89. template <typename R, typename... Args>
  90. struct function_traits<R(Args...)> : public function_traits_base<R, Args...> {};
  91. template <typename F>
  92. using function_arg_sequence = typename function_traits<F>::arg_types;
  93.  
  94.  
  95. /**************************
  96.  * Stuff to call the function invariably
  97.  * ************************/
  98.  
  99. template<typename F>
  100. struct func_caller
  101. {
  102. static_assert(has_operator_func<F>::value || std::is_function<F>::value,
  103. "Only functions, functors, etc. may be used with 'func_caller'");
  104. typedef typename function_traits<F>::result_type result_type;
  105.  
  106. template<typename... Args, size_t... Ints>
  107. static inline result_type real_call(const std::function<result_type(Args...)>& func, index_sequence<Ints...>)
  108. {
  109. return func(Rand<Args>::get(Ints)...);
  110. }
  111.  
  112. template<typename... Args>
  113. static inline result_type call_typed(const F& func, type_sequence<Args...>)
  114. {
  115. return real_call(std::function<result_type(Args...)>(func), index_sequence_for<Args...>{});
  116. }
  117.  
  118. static inline result_type call(const F& func)
  119. {
  120. return call_typed(func, function_arg_sequence<F>{});
  121. }
  122. };
  123.  
  124. template <typename R, typename... Args>
  125. struct func_caller<R(Args...)>
  126. {
  127. typedef R result_type;
  128.  
  129. template<size_t... Ints>
  130. static inline R real_call(const std::function<R(Args...)>& func, index_sequence<Ints...>)
  131. {
  132. return func(Rand<Args>::get(Ints)...);
  133. }
  134.  
  135. template <typename F>
  136. static inline R call_typed(const F& func)
  137. {
  138. return real_call(std::function<R(Args...)>(func), index_sequence_for<Args...>{});
  139. }
  140.  
  141. static inline R call(R (*func)(Args...))
  142. {
  143. return call_typed(func);
  144. }
  145. };
  146.  
  147. /* In a real world use, something like this might be useful
  148. instead of calling func_caller immediately, so as to exit the compile easier...
  149. In this example, on ideone.com, you still get pretty gnarly compile errors, though
  150. it should be obvious what the problem is early on ;)
  151. template <typename F>
  152. struct call_func_proof
  153. {
  154. static_assert(has_operator_func<F>::value || std::is_function<F>::value,
  155. "Only functions, functors, etc. may be passed to 'call_func'");
  156.  
  157. static inline auto call_func(const F& func) ->
  158. decltype(func_caller<F>::call(func))
  159. {
  160. return func_caller<F>::call(func);
  161. }
  162. };
  163. */
  164.  
  165. template <typename F>
  166. static inline auto call_func(const F& func) -> decltype(func_caller<F>::call(func))
  167. {
  168. return func_caller<F>::call(func);
  169. }
  170.  
  171. template <typename FType, typename F>
  172. static inline auto call_func_t(const F& func) -> decltype(func_caller<FType>::call_typed(func))
  173. {
  174. return func_caller<FType>::call_typed(func);
  175. }
  176.  
  177.  
  178. /**************************
  179.  * And example using it
  180.  * ************************/
  181.  
  182. void test_func(int i1, double d1, int i2, std::string str1, std::string str2, double d2)
  183. {
  184. std::cout << i1 << ", " << d1 << ", " << i2 << ", " << str1 << ", " << str2 << ", " << d2 << std::endl;
  185. }
  186.  
  187. struct test_obj
  188. {
  189. void operator()(double d1, std::string str1, double d2, double d3, int i, std::string str2, double d4)
  190. {
  191. std::cout << d1 << ", " << str1 << ", " << d2 << ", " << d3 << ", " << i << ", " << str2 << ", " << d4 << std::endl;
  192. }
  193.  
  194. void operator()()
  195. {
  196. std::cout << "O.o" << std::endl;
  197. } // This throws an error with call_func, because the overloaded () can't be resolved. call_func_t is required
  198. };
  199.  
  200. int main() {
  201. call_func(
  202. [](int i, std::string str1, std::string str2, double d)
  203. {
  204. std::cout << i << ", " << str1 << ", " << str2 << ", " << d << std::endl;
  205. });
  206. std::string stated_str = "My str";
  207. call_func(
  208. [&](int i, double d, std::string s)
  209. {
  210. std::cout << stated_str << ", " << i << ", " << d << ", " << s << std::endl;
  211. });
  212. call_func(test_func);
  213. //call_func(test_obj{});
  214. call_func_t<void(double, std::string, double, double, int, std::string, double)>(test_obj{});
  215.  
  216. using namespace std::placeholders;
  217. call_func(std::function<void(double, int, std::string, double)>(
  218. std::bind(test_func, 634, _1, _2, "This one's messed up", _3, _4)));
  219.  
  220. //compile error, with some fluff, but nicely does say
  221. //Only functions, functors, etc. may be used with 'func_caller'
  222. //Further down in the compile errors:
  223. //"function_traits may only on objecst with operator() or defined functions"
  224. //and:
  225. //'operator()' is not a member of 'bool'
  226. //call_func(true);
  227. return 0;
  228. }
Success #stdin #stdout 0s 3448KB
stdin
Standard input is empty
stdout
100, Text (1), Text (2), 3.001
My str, 100, 1.001, Text (2)
100, 1.001, 102, Text (3), Text (4), 5.001
0.001, Text (1), 2.001, 3.001, 104, Text (5), 6.001
634, 0.001, 101, This one's messed up, Text (2), 3.001