Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

187 lines
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__ */