fork download
  1.  
  2. #include <iostream>
  3. #include <type_traits>
  4. #include <functional>
  5.  
  6. ////////////////////////////////////////////////////////////////////////////////
  7. // Detection idiom, from C++ Library fundamentals extension in N4436
  8.  
  9. namespace std {
  10. namespace experimental {
  11.  
  12. // A void_t implementation that works with gcc-4.9 (workaround for bug 64395
  13. // From: http://stackoverflow.com/questions/35753920/why-does-the-void-t-detection-idiom-not-work-with-gcc-4-9
  14. namespace _void_t_impl {
  15.  
  16. template <class... >
  17. struct make_void { using type = void; };
  18.  
  19. } // end namepace _void_t_impl
  20.  
  21. template <class... T>
  22. using void_t = typename _void_t_impl::make_void<T...>::type;
  23.  
  24. template <
  25. class Default,
  26. class _always_void,
  27. template <class...> class Op,
  28. class... Args
  29. >
  30. struct detector {
  31. constexpr static auto value = false;
  32. using type = Default;
  33. };
  34.  
  35. // specialization recognizes and handles only types supporting Op
  36. template <
  37. class Default,
  38. template <class...> class Op,
  39. class... Args
  40. >
  41. struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
  42. constexpr static auto value = true;
  43. using type = Op<Args...>;
  44. };
  45.  
  46. struct nonesuch {
  47. nonesuch() = delete;
  48. ~nonesuch() = delete;
  49. nonesuch(nonesuch const&) = delete;
  50. void operator=(nonesuch const&) = delete;
  51. constexpr static auto value = false;
  52. };
  53.  
  54. template <template <class...> class Op, class... Args>
  55. using is_detected = detector<nonesuch, void, Op, Args...>;
  56.  
  57. template <template <class...> class Op, class... Args>
  58. using detected_t = typename is_detected<Op, Args...>::type;
  59.  
  60. template <class Default, template <class...> class Op, class... Args>
  61. using detected_or = detector<Default, void, Op, Args...>;
  62.  
  63. template <class Default, template <class...> class Op, class... Args>
  64. using detected_or_t = typename detected_or<Default, Op, Args...>::type;
  65.  
  66. template <class Expected, template<class...> class Op, class... Args>
  67. using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
  68.  
  69. template <class To, template <class...> class Op, class... Args>
  70. using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>;
  71.  
  72. } // end namespace experimental
  73. } // end namespace std
  74.  
  75. ////////////////////////////////////////////////////////////////////////////////
  76.  
  77. using namespace std;
  78. using namespace std::experimental;
  79.  
  80. static constexpr auto max_num_args = 127;
  81.  
  82. struct any {
  83. template <typename T,
  84. typename = enable_if_t<
  85. not is_same<T, remove_reference_t<T>>::value
  86. >
  87. >
  88. operator T();
  89. template <typename T,
  90. typename = enable_if_t<
  91. is_same<T, remove_reference_t<T>>::value
  92. >
  93. >
  94. operator T&();
  95. template <typename T,
  96. typename = enable_if_t<
  97. is_same<T, remove_reference_t<T>>::value
  98. >
  99. >
  100. operator T&&();
  101. };
  102.  
  103.  
  104. template <typename F, typename... Args>
  105. using callable_archetype = decltype( declval<F>()(declval<Args>()...) );
  106. template <typename F, typename... Args>
  107. using is_callable_with_args = is_detected<callable_archetype, F, Args...>;
  108.  
  109. template <typename F, size_t I = 0, typename... Args>
  110. struct count_args
  111. : conditional<
  112. is_callable_with_args<F, Args...>::value,
  113. integral_constant<size_t, I>,
  114. count_args<F, I+1, Args..., any>
  115. >::type::type
  116. { };
  117.  
  118. template <typename F, typename... Args>
  119. struct count_args<F, max_num_args, Args...> : integral_constant<size_t, max_num_args> { };
  120.  
  121. // Some example cases
  122.  
  123. void foo(int i, int j) { }
  124. struct bar {
  125. void operator()(std::string const&, std::ostream const&, int) const { }
  126. };
  127. void baz(std::string&, const std::string&) { }
  128.  
  129. int main(int argc, char** argv) {
  130. cout << count_args<decltype(foo)>::value << endl; // Should be 2
  131. cout << count_args<bar>::value << endl; // should be 3
  132. cout << count_args<decltype(baz)>::value << endl; // fails because of lvalue reference!
  133. }
  134.  
  135.  
Success #stdin #stdout 0s 3412KB
stdin
Standard input is empty
stdout
2
3
2