Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

228 lignes
7.5 KiB

  1. /*!
  2. * \file utl/utility/invoke.h
  3. * \brief invoke() and invoke traits implementation
  4. */
  5. #ifndef __utl_utility_invoke_h__
  6. #define __utl_utility_invoke_h__
  7. #include <utl/core/impl.h>
  8. #include <utl/meta/meta.h>
  9. #include <type_traits>
  10. #include <functional>
  11. #include <utility>
  12. //! \defgroup utility Utility
  13. /*!
  14. * \ingroup utility
  15. * \defgroup util_invoke Invoke
  16. */
  17. //! @{
  18. namespace utl {
  19. #if !defined __cpp_lib_is_invocable
  20. namespace detail {
  21. template <class T>
  22. struct is_ref_wrapper : meta::false_ {};
  23. template <class U>
  24. struct is_ref_wrapper<std::reference_wrapper<U>> : meta::true_ {};
  25. // 1
  26. template <class T, class Type, class T1, class... Args,
  27. meta::enable_if_t<
  28. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  29. std::is_base_of<T, std::decay_t<T1>>::value,
  30. int> =0
  31. >
  32. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  33. return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
  34. }
  35. // 2
  36. template <class T, class Type, class T1, class... Args,
  37. meta::enable_if_t<
  38. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  39. is_ref_wrapper<std::decay_t<T1>>::value,
  40. int> =0
  41. >
  42. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  43. return (t1.get().*f)(std::forward<Args>(args)...);
  44. }
  45. // 3
  46. template <class T, class Type, class T1, class... Args,
  47. meta::enable_if_t<
  48. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  49. !std::is_base_of<T, std::decay_t<T1>>::value &&
  50. !is_ref_wrapper<std::decay_t<T1>>::value,
  51. int> =0
  52. >
  53. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  54. return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
  55. }
  56. // 4
  57. template <class T, class Type, class T1, class... Args,
  58. meta::enable_if_t<
  59. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  60. std::is_base_of<T, std::decay_t<T1>>::value,
  61. int> =0
  62. >
  63. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  64. return std::forward<T1>(t1).*f;
  65. }
  66. // 5
  67. template <class T, class Type, class T1, class... Args,
  68. meta::enable_if_t<
  69. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  70. is_ref_wrapper<std::decay_t<T1>>::value,
  71. int> =0
  72. >
  73. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  74. return t1.get().*f;
  75. }
  76. // 6
  77. template <class T, class Type, class T1, class... Args,
  78. meta::enable_if_t<
  79. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  80. !std::is_base_of<T, std::decay_t<T1>>::value &&
  81. !is_ref_wrapper<std::decay_t<T1>>::value,
  82. int> =0
  83. >
  84. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  85. return (*std::forward<T1>(t1)).*f;
  86. }
  87. template <class F, class... Args>
  88. decltype(auto) invoke_impl_(F&& f, Args&&... args) {
  89. return std::forward<F>(f)(std::forward<Args>(args)...);
  90. }
  91. } // namespace detail
  92. //! Invoke the Callable object \c fn with the parameters args.
  93. //! As by INVOKE(std::forward<F>(f), std::forward<Args>(args)...).
  94. //!
  95. //! \note
  96. //! This implementation fills the lack of an invoke() utility for builds
  97. //! pre-c++17.
  98. //!
  99. //! \param fn Callable object to be invoked
  100. //! \param args Arguments to pass to \c fn
  101. //! \return The return of the Callable underling functionality
  102. //!
  103. template<typename Callable, typename... Args>
  104. inline decltype(auto) invoke(Callable&& fn, Args&&... args) {
  105. return detail::invoke_impl_(
  106. std::forward<Callable>(fn), std::forward<Args>(args)...
  107. );
  108. }
  109. //!
  110. //! \brief
  111. //! Determines whether \c F can be invoked with the arguments \c Args....
  112. //!
  113. //! Formally, determines whether invoke(declval<Fn>(), declval<ArgTypes>()...)
  114. //! is well formed when treated as an unevaluated operand,
  115. //! where invoke is \c Callable.
  116. //!
  117. //! \note
  118. //! This implementation fills the lack of an invoke() utility for builds
  119. //! pre-c++17.
  120. //!
  121. //! \tparam F The candidate type to check if its invocable
  122. //! \tparam Args The arguments for the call
  123. //! \return If \c F is invocable
  124. //! \arg true Is invocable
  125. //! \arg false Is not invocable
  126. template <typename F, typename... Args>
  127. struct is_invocable :
  128. std::is_constructible<
  129. std::function<void(Args ...)>,
  130. std::reference_wrapper<typename std::remove_reference<F>::type>
  131. > { };
  132. //! \brief
  133. //! Determines whether \c F can be invoked with the arguments \c Args...
  134. //! to yield a result that is convertible to \c R.
  135. //!
  136. //! Formally, determines whether invoke(declval<Fn>(), declval<ArgTypes>()...)
  137. //! is well formed when treated as an unevaluated operand, where invoke is \c Callable.
  138. //!
  139. //! \tparam R The return type of invocable functionality
  140. //! \tparam F The candidate type to check if its invocable
  141. //! \tparam Args The arguments to pass to \c F
  142. //! \return If \c F is invocable
  143. //! \arg true Is invocable
  144. //! \arg false Is not invocable
  145. template <typename R, typename F, typename... Args>
  146. struct is_invocable_r :
  147. std::is_constructible<
  148. std::function<R(Args ...)>,
  149. std::reference_wrapper<typename std::remove_reference<F>::type>
  150. > { };
  151. /*!
  152. * invoke_result (SFINAE friendly)
  153. */
  154. //! @{
  155. namespace detail {
  156. template<typename Callable, typename... Args>
  157. struct try_invoke {
  158. using type = decltype (
  159. detail::invoke_impl_(std::declval<Callable&&>(), std::declval<Args&&>()...)
  160. );
  161. };
  162. template<bool B, typename Callable, typename... Args>
  163. struct invoke_result_ {
  164. using type = meta::nil_;
  165. };
  166. template <typename Callable, typename... Args>
  167. struct invoke_result_ <true, Callable, Args...> {
  168. using type = meta::invoke_t<
  169. meta::quote<try_invoke>, Callable, Args...
  170. >;
  171. };
  172. }
  173. //! trait that deduces the return type of an INVOKE expression at compile time.
  174. //!
  175. //! \tparam Callable The candidate type to check if its invocable
  176. //! \tparam Args The arguments to pass to \c F
  177. //!
  178. //! \b member \n
  179. //! \::type The return type of the \c Callable type if invoked with the arguments Args....
  180. template <typename Callable, typename... Args>
  181. using invoke_result = detail::invoke_result_<
  182. is_invocable<Callable, Args...>::value,
  183. Callable,
  184. Args...
  185. >;
  186. //! trait that deduces the return type of an INVOKE expression at compile time.
  187. //!
  188. //! \tparam Callable The candidate type to check if its invocable
  189. //! \tparam Args The arguments to pass to \c F
  190. //!
  191. //! \return The type of the \c Callable type if invoked with the arguments Args....
  192. template<typename Callable, typename... Args>
  193. using invoke_result_t = meta::eval <
  194. invoke_result<Callable, Args...>
  195. >;
  196. //! @}
  197. #else
  198. #endif
  199. }
  200. //! @}
  201. #endif /* __utl_utility_invoke_h__ */