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.
 
 
 
 

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