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.
 
 
 
 

187 lignes
6.0 KiB

  1. /*!
  2. * \file utl/utility/invoke.h
  3. * \brief invoke() and invoke traits implementation
  4. *
  5. * Copyright (C) 2018-2019 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more detail.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #ifndef __utl_utility_invoke_h__
  21. #define __utl_utility_invoke_h__
  22. #include <utl/core/impl.h>
  23. #include <utl/meta/meta.h>
  24. #include <type_traits>
  25. #include <functional>
  26. #include <utility>
  27. /*!
  28. * \ingroup utility
  29. * \defgroup invoke
  30. */
  31. //! @{
  32. namespace utl {
  33. namespace detail {
  34. template <class T>
  35. struct is_ref_wrapper : meta::false_ {};
  36. template <class U>
  37. struct is_ref_wrapper<std::reference_wrapper<U>> : meta::true_ {};
  38. // 1
  39. template <class T, class Type, class T1, class... Args,
  40. meta::enable_if_t<
  41. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  42. std::is_base_of<T, std::decay_t<T1>>::value,
  43. int> =0
  44. >
  45. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  46. return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
  47. }
  48. // 2
  49. template <class T, class Type, class T1, class... Args,
  50. meta::enable_if_t<
  51. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  52. is_ref_wrapper<std::decay_t<T1>>::value,
  53. int> =0
  54. >
  55. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  56. return (t1.get().*f)(std::forward<Args>(args)...);
  57. }
  58. // 3
  59. template <class T, class Type, class T1, class... Args,
  60. meta::enable_if_t<
  61. std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
  62. !std::is_base_of<T, std::decay_t<T1>>::value &&
  63. !is_ref_wrapper<std::decay_t<T1>>::value,
  64. int> =0
  65. >
  66. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  67. return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
  68. }
  69. // 4
  70. template <class T, class Type, class T1, class... Args,
  71. meta::enable_if_t<
  72. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  73. std::is_base_of<T, std::decay_t<T1>>::value,
  74. int> =0
  75. >
  76. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  77. return std::forward<T1>(t1).*f;
  78. }
  79. // 5
  80. template <class T, class Type, class T1, class... Args,
  81. meta::enable_if_t<
  82. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  83. is_ref_wrapper<std::decay_t<T1>>::value,
  84. int> =0
  85. >
  86. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  87. return t1.get().*f;
  88. }
  89. // 6
  90. template <class T, class Type, class T1, class... Args,
  91. meta::enable_if_t<
  92. std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
  93. !std::is_base_of<T, std::decay_t<T1>>::value &&
  94. !is_ref_wrapper<std::decay_t<T1>>::value,
  95. int> =0
  96. >
  97. decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
  98. return (*std::forward<T1>(t1)).*f;
  99. }
  100. template <class F, class... Args>
  101. decltype(auto) invoke_impl_(F&& f, Args&&... args) {
  102. return std::forward<F>(f)(std::forward<Args>(args)...);
  103. }
  104. } // namespace detail
  105. //! Invoke a callable object (for C++14)
  106. template<typename _Callable, typename... _Args>
  107. inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) {
  108. return detail::invoke_impl_(
  109. std::forward<_Callable>(fn), std::forward<_Args>(args)...
  110. );
  111. }
  112. //! @}
  113. //! std::is_invocable trait for C++11
  114. template <typename F, typename... Args>
  115. struct is_invocable :
  116. std::is_constructible<
  117. std::function<void(Args ...)>,
  118. std::reference_wrapper<typename std::remove_reference<F>::type>
  119. > { };
  120. //! std::is_invocable_r trait for C++11
  121. template <typename R, typename F, typename... Args>
  122. struct is_invocable_r :
  123. std::is_constructible<
  124. std::function<R(Args ...)>,
  125. std::reference_wrapper<typename std::remove_reference<F>::type>
  126. > { };
  127. /*!
  128. * invoke_result (SFINAE friendly)
  129. */
  130. //! @{
  131. namespace detail {
  132. template<typename _Callable, typename... _Args>
  133. struct try_invoke {
  134. using type = decltype (
  135. detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...)
  136. );
  137. };
  138. template<bool B, typename _Callable, typename... _Args>
  139. struct invoke_result_ {
  140. using type = meta::nil_;
  141. };
  142. template <typename _Callable, typename... _Args>
  143. struct invoke_result_ <true, _Callable, _Args...> {
  144. using type = meta::invoke_t<
  145. meta::quote<try_invoke>, _Callable, _Args...
  146. >;
  147. };
  148. }
  149. //! invoke_result (for C++14)
  150. template <typename _Callable, typename... _Args>
  151. using invoke_result = detail::invoke_result_<
  152. is_invocable<_Callable, _Args...>::value,
  153. _Callable,
  154. _Args...
  155. >;
  156. //! invoke_result_t (for C++14)
  157. template<typename _Callable, typename... _Args>
  158. using invoke_result_t = meta::eval <
  159. invoke_result<_Callable, _Args...>
  160. >;
  161. }
  162. //! @}
  163. #endif /* __utl_utility_invoke_h__ */