function_traits.hpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. *
  10. * refrenced from : https://github.com/qicosmos/rest_rpc/blob/master/include/meta_util.hpp
  11. */
  12. #ifndef __ASIO2_FUNCTION_TRAITS_HPP__
  13. #define __ASIO2_FUNCTION_TRAITS_HPP__
  14. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #pragma once
  16. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  17. #include <functional>
  18. #include <type_traits>
  19. namespace asio2::detail
  20. {
  21. template<typename, typename = void>
  22. struct lambda_dummy_t { };
  23. template<typename Ret, typename... Args>
  24. struct lambda_dummy_t<Ret(Args...)>
  25. {
  26. template<typename R = Ret>
  27. inline R operator()(const Args&...)
  28. {
  29. if /**/ constexpr (std::is_same_v<void, std::remove_cv_t<std::remove_reference_t<R>>>)
  30. {
  31. return;
  32. }
  33. else if constexpr (std::is_reference_v<std::remove_cv_t<R>>)
  34. {
  35. static typename std::remove_reference_t<R> s;
  36. return s;
  37. }
  38. else
  39. {
  40. return R{};
  41. }
  42. }
  43. };
  44. /*
  45. * 1. function type ==> Ret(Args...)
  46. * 2. function pointer ==> Ret(*)(Args...)
  47. * 3. function reference ==> Ret(&)(Args...)
  48. * 4. pointer to non-static member function ==> Ret(T::*)(Args...)
  49. * 5. function object and functor ==> &T::operator()
  50. * 6. function with generic operator call ==> template <typeanme ... Args> &T::operator()
  51. */
  52. template<typename, typename = void>
  53. struct function_traits { static constexpr bool is_callable = false; };
  54. template<typename Ret, typename... Args>
  55. struct function_traits<Ret(Args...)>
  56. {
  57. public:
  58. static constexpr std::size_t argc = sizeof...(Args);
  59. static constexpr bool is_callable = true;
  60. typedef Ret function_type(Args...);
  61. typedef Ret return_type;
  62. using stl_function_type = std::function<function_type>;
  63. using stl_lambda_type = lambda_dummy_t<function_type>;
  64. typedef Ret(*pointer)(Args...);
  65. using class_type = void;
  66. template<std::size_t I>
  67. struct args
  68. {
  69. static_assert(I < argc, "index is out of range, index must less than sizeof Args");
  70. using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
  71. };
  72. typedef std::tuple<Args...> tuple_type;
  73. typedef std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> pod_tuple_type;
  74. };
  75. template<typename Class, typename Ret, typename... Args>
  76. struct function_traits<Class, Ret(Args...)>
  77. {
  78. public:
  79. static constexpr std::size_t argc = sizeof...(Args);
  80. static constexpr bool is_callable = true;
  81. typedef Ret function_type(Args...);
  82. typedef Ret return_type;
  83. using stl_function_type = std::function<function_type>;
  84. using stl_lambda_type = lambda_dummy_t<function_type>;
  85. typedef Ret(*pointer)(Args...);
  86. using class_type = Class;
  87. template<std::size_t I>
  88. struct args
  89. {
  90. static_assert(I < argc, "index is out of range, index must less than sizeof Args");
  91. using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
  92. };
  93. typedef std::tuple<Args...> tuple_type;
  94. typedef std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> pod_tuple_type;
  95. };
  96. // regular function pointer
  97. template<typename Ret, typename... Args>
  98. struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)> {};
  99. // non-static member function pointer
  100. template <typename Ret, typename Class, typename... Args>
  101. struct function_traits<Ret(Class::*)(Args...)> : function_traits<Class, Ret(Args...)> {};
  102. template <typename Ret, typename Class, typename... Args>
  103. struct function_traits<Ret(Class::*)(Args...) const> : function_traits<Class, Ret(Args...)> {};
  104. template <typename Ret, typename Class, typename... Args>
  105. struct function_traits<Ret(Class::*)(Args...) volatile> : function_traits<Class, Ret(Args...)> {};
  106. template <typename Ret, typename Class, typename... Args>
  107. struct function_traits<Ret(Class::*)(Args...) const volatile> : function_traits<Class, Ret(Args...)> {};
  108. template <typename Ret, typename Class, typename... Args>
  109. struct function_traits<Ret(Class::*)(Args...) &> : function_traits<Class, Ret(Args...)> {};
  110. template <typename Ret, typename Class, typename... Args>
  111. struct function_traits<Ret(Class::*)(Args...) const &> : function_traits<Class, Ret(Args...)> {};
  112. template <typename Ret, typename Class, typename... Args>
  113. struct function_traits<Ret(Class::*)(Args...) volatile &> : function_traits<Class, Ret(Args...)> {};
  114. template <typename Ret, typename Class, typename... Args>
  115. struct function_traits<Ret(Class::*)(Args...) const volatile &> : function_traits<Class, Ret(Args...)> {};
  116. template <typename Ret, typename Class, typename... Args>
  117. struct function_traits<Ret(Class::*)(Args...) && > : function_traits<Class, Ret(Args...)> {};
  118. template <typename Ret, typename Class, typename... Args>
  119. struct function_traits<Ret(Class::*)(Args...) const &&> : function_traits<Class, Ret(Args...)> {};
  120. template <typename Ret, typename Class, typename... Args>
  121. struct function_traits<Ret(Class::*)(Args...) volatile &&> : function_traits<Class, Ret(Args...)> {};
  122. template <typename Ret, typename Class, typename... Args>
  123. struct function_traits<Ret(Class::*)(Args...) const volatile &&> : function_traits<Class, Ret(Args...)> {};
  124. // non-static member function pointer -- noexcept versions for (C++17 and later)
  125. template <typename Ret, typename Class, typename... Args>
  126. struct function_traits<Ret(Class::*)(Args...) noexcept> : function_traits<Class, Ret(Args...)> {};
  127. template <typename Ret, typename Class, typename... Args>
  128. struct function_traits<Ret(Class::*)(Args...) const noexcept> : function_traits<Class, Ret(Args...)> {};
  129. template <typename Ret, typename Class, typename... Args>
  130. struct function_traits<Ret(Class::*)(Args...) volatile noexcept> : function_traits<Class, Ret(Args...)> {};
  131. template <typename Ret, typename Class, typename... Args>
  132. struct function_traits<Ret(Class::*)(Args...) const volatile noexcept> : function_traits<Class, Ret(Args...)> {};
  133. template <typename Ret, typename Class, typename... Args>
  134. struct function_traits<Ret(Class::*)(Args...) & noexcept> : function_traits<Class, Ret(Args...)> {};
  135. template <typename Ret, typename Class, typename... Args>
  136. struct function_traits<Ret(Class::*)(Args...) const & noexcept> : function_traits<Class, Ret(Args...)> {};
  137. template <typename Ret, typename Class, typename... Args>
  138. struct function_traits<Ret(Class::*)(Args...) volatile & noexcept> : function_traits<Class, Ret(Args...)> {};
  139. template <typename Ret, typename Class, typename... Args>
  140. struct function_traits<Ret(Class::*)(Args...) const volatile& noexcept>
  141. : function_traits<Class, Ret(Args...)> {};
  142. template <typename Ret, typename Class, typename... Args>
  143. struct function_traits<Ret(Class::*)(Args...) && noexcept> : function_traits<Class, Ret(Args...)> {};
  144. template <typename Ret, typename Class, typename... Args>
  145. struct function_traits<Ret(Class::*)(Args...) const && noexcept> : function_traits<Class, Ret(Args...)> {};
  146. template <typename Ret, typename Class, typename... Args>
  147. struct function_traits<Ret(Class::*)(Args...) volatile && noexcept> : function_traits<Class, Ret(Args...)> {};
  148. template <typename Ret, typename Class, typename... Args>
  149. struct function_traits<Ret(Class::*)(Args...) const volatile&& noexcept>
  150. : function_traits<Class, Ret(Args...)> {};
  151. // functor lambda
  152. template<typename Callable>
  153. struct function_traits<Callable, std::void_t<decltype(&Callable::operator()), char>>
  154. : function_traits<decltype(&Callable::operator())> {};
  155. // std::function
  156. template <typename Ret, typename... Args>
  157. struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)> {};
  158. template <typename F>
  159. typename function_traits<F>::stl_function_type to_function(F&& lambda)
  160. {
  161. return static_cast<typename function_traits<F>::stl_function_type>(std::forward<F>(lambda));
  162. }
  163. template <typename F>
  164. typename function_traits<F>::pointer to_function_pointer(const F& lambda) noexcept
  165. {
  166. return static_cast<typename function_traits<F>::pointer>(lambda);
  167. }
  168. template< class F >
  169. inline constexpr bool is_callable_v = function_traits<std::decay_t<F>>::is_callable;
  170. template<typename F, typename Void, typename... Args>
  171. struct is_template_callable : std::false_type {};
  172. template<typename F, typename... Args>
  173. struct is_template_callable<F, std::void_t<decltype(std::declval<std::decay_t<F>&>()
  174. ((std::declval<Args>())...)), char>, Args...> : std::true_type {};
  175. template<typename F, typename... Args>
  176. inline constexpr bool is_template_callable_v = is_template_callable<F, void, Args...>::value;
  177. }
  178. #endif // !__ASIO2_FUNCTION_TRAITS_HPP__