Micro template library A library for building device drivers
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

172 行
5.3 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. /*!
  13. * \ingroup utility
  14. * \defgroup invoke Invoke
  15. */
  16. //! @{
  17. namespace utl {
  18. namespace detail {
  19. template <class T>
  20. struct is_ref_wrapper : meta::false_ {};
  21. template <class U>
  22. struct is_ref_wrapper<std::reference_wrapper<U>> : meta::true_ {};
  23. // 1
  24. template <class T, class Type, class T1, class... Args,
  25. meta::enable_if_t<
  26. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  27. std::is_base_of<T, std::decay_t<T1>>::value,
  28. int> =0
  29. >
  30. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  31. return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
  32. }
  33. // 2
  34. template <class T, class Type, class T1, class... Args,
  35. meta::enable_if_t<
  36. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  37. is_ref_wrapper<std::decay_t<T1>>::value,
  38. int> =0
  39. >
  40. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  41. return (t1.get().*f)(std::forward<Args>(args)...);
  42. }
  43. // 3
  44. template <class T, class Type, class T1, class... Args,
  45. meta::enable_if_t<
  46. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  47. !std::is_base_of<T, std::decay_t<T1>>::value &&
  48. !is_ref_wrapper<std::decay_t<T1>>::value,
  49. int> =0
  50. >
  51. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  52. return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
  53. }
  54. // 4
  55. template <class T, class Type, class T1, class... Args,
  56. meta::enable_if_t<
  57. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  58. std::is_base_of<T, std::decay_t<T1>>::value,
  59. int> =0
  60. >
  61. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  62. return std::forward<T1>(t1).*f;
  63. }
  64. // 5
  65. template <class T, class Type, class T1, class... Args,
  66. meta::enable_if_t<
  67. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  68. is_ref_wrapper<std::decay_t<T1>>::value,
  69. int> =0
  70. >
  71. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  72. return t1.get().*f;
  73. }
  74. // 6
  75. template <class T, class Type, class T1, class... Args,
  76. meta::enable_if_t<
  77. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  78. !std::is_base_of<T, std::decay_t<T1>>::value &&
  79. !is_ref_wrapper<std::decay_t<T1>>::value,
  80. int> =0
  81. >
  82. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  83. return (*std::forward<T1>(t1)).*f;
  84. }
  85. template <class F, class... Args>
  86. decltype(auto) invoke_impl_(F&& f, Args&&... args) {
  87. return std::forward<F>(f)(std::forward<Args>(args)...);
  88. }
  89. } // namespace detail
  90. //! Invoke a callable object (for C++14)
  91. template<typename _Callable, typename... _Args>
  92. inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) {
  93. return detail::invoke_impl_(
  94. std::forward<_Callable>(fn), std::forward<_Args>(args)...
  95. );
  96. }
  97. //! @}
  98. //! std::is_invocable trait for C++14
  99. template <typename F, typename... Args>
  100. struct is_invocable :
  101. std::is_constructible<
  102. std::function<void(Args ...)>,
  103. std::reference_wrapper<typename std::remove_reference<F>::type>
  104. > { };
  105. //! std::is_invocable_r trait for C++14
  106. template <typename R, typename F, typename... Args>
  107. struct is_invocable_r :
  108. std::is_constructible<
  109. std::function<R(Args ...)>,
  110. std::reference_wrapper<typename std::remove_reference<F>::type>
  111. > { };
  112. /*!
  113. * invoke_result (SFINAE friendly)
  114. */
  115. //! @{
  116. namespace detail {
  117. template<typename _Callable, typename... _Args>
  118. struct try_invoke {
  119. using type = decltype (
  120. detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...)
  121. );
  122. };
  123. template<bool B, typename _Callable, typename... _Args>
  124. struct invoke_result_ {
  125. using type = meta::nil_;
  126. };
  127. template <typename _Callable, typename... _Args>
  128. struct invoke_result_ <true, _Callable, _Args...> {
  129. using type = meta::invoke_t<
  130. meta::quote<try_invoke>, _Callable, _Args...
  131. >;
  132. };
  133. }
  134. //! invoke_result (for C++14)
  135. template <typename _Callable, typename... _Args>
  136. using invoke_result = detail::invoke_result_<
  137. is_invocable<_Callable, _Args...>::value,
  138. _Callable,
  139. _Args...
  140. >;
  141. //! invoke_result_t (for C++14)
  142. template<typename _Callable, typename... _Args>
  143. using invoke_result_t = meta::eval <
  144. invoke_result<_Callable, _Args...>
  145. >;
  146. }
  147. //! @}
  148. #endif /* __utl_utility_invoke_h__ */