invoke.hpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Casey Carter 2016
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_FUNCTIONAL_INVOKE_HPP
  15. #define RANGES_V3_FUNCTIONAL_INVOKE_HPP
  16. #include <functional>
  17. #include <type_traits>
  18. #include <meta/meta.hpp>
  19. #include <concepts/concepts.hpp>
  20. #include <range/v3/range_fwd.hpp>
  21. #include <range/v3/utility/static_const.hpp>
  22. #include <range/v3/detail/prologue.hpp>
  23. RANGES_DIAGNOSTIC_PUSH
  24. RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT
  25. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  26. #ifndef RANGES_CONSTEXPR_INVOKE
  27. #ifdef RANGES_WORKAROUND_CLANG_23135
  28. #define RANGES_CONSTEXPR_INVOKE 0
  29. #else
  30. #define RANGES_CONSTEXPR_INVOKE 1
  31. #endif
  32. #endif
  33. namespace ranges
  34. {
  35. /// \addtogroup group-functional
  36. /// @{
  37. /// \cond
  38. namespace detail
  39. {
  40. RANGES_DIAGNOSTIC_PUSH
  41. RANGES_DIAGNOSTIC_IGNORE_VOID_PTR_DEREFERENCE
  42. template<typename U>
  43. U & can_reference_(U &&);
  44. // clang-format off
  45. /// \concept dereferenceable_part_
  46. /// \brief The \c dereferenceable_part_ concept
  47. template<typename T>
  48. CPP_requires(dereferenceable_part_,
  49. requires(T && t) //
  50. (
  51. detail::can_reference_(*(T &&) t)
  52. ));
  53. /// \concept dereferenceable_
  54. /// \brief The \c dereferenceable_ concept
  55. template<typename T>
  56. CPP_concept dereferenceable_ = //
  57. CPP_requires_ref(detail::dereferenceable_part_, T);
  58. // clang-format on
  59. RANGES_DIAGNOSTIC_POP
  60. template<typename T>
  61. RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v =
  62. meta::is<T, reference_wrapper>::value ||
  63. meta::is<T, std::reference_wrapper>::value;
  64. } // namespace detail
  65. /// \endcond
  66. template<typename T>
  67. RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v =
  68. detail::is_reference_wrapper_v<detail::decay_t<T>>;
  69. template<typename T>
  70. using is_reference_wrapper = meta::bool_<is_reference_wrapper_v<T>>;
  71. /// \cond
  72. template<typename T>
  73. using is_reference_wrapper_t RANGES_DEPRECATED(
  74. "is_reference_wrapper_t is deprecated.") = meta::_t<is_reference_wrapper<T>>;
  75. /// \endcond
  76. struct invoke_fn
  77. {
  78. private:
  79. template(typename, typename T1)(
  80. requires detail::dereferenceable_<T1>)
  81. static constexpr decltype(auto) coerce(T1 && t1, long)
  82. noexcept(noexcept(*static_cast<T1 &&>(t1)))
  83. {
  84. return *static_cast<T1 &&>(t1);
  85. }
  86. template(typename T, typename T1)(
  87. requires derived_from<detail::decay_t<T1>, T>)
  88. static constexpr T1 && coerce(T1 && t1, int) noexcept
  89. {
  90. return static_cast<T1 &&>(t1);
  91. }
  92. template(typename, typename T1)(
  93. requires detail::is_reference_wrapper_v<detail::decay_t<T1>>)
  94. static constexpr decltype(auto) coerce(T1 && t1, int) noexcept
  95. {
  96. return static_cast<T1 &&>(t1).get();
  97. }
  98. public:
  99. template<typename F, typename T, typename T1, typename... Args>
  100. constexpr auto operator()(F T::*f, T1&& t1, Args&&... args) const
  101. noexcept(noexcept((invoke_fn::coerce<T>((T1&&) t1, 0).*f)((Args&&) args...)))
  102. -> decltype((invoke_fn::coerce<T>((T1&&) t1, 0).*f)((Args&&) args...))
  103. {
  104. return (invoke_fn::coerce<T>((T1&&) t1, 0).*f)((Args&&) args...);
  105. }
  106. template<typename D, typename T, typename T1>
  107. constexpr auto operator()(D T::*f, T1&& t1) const
  108. noexcept(noexcept(invoke_fn::coerce<T>((T1&&) t1, 0).*f))
  109. -> decltype(invoke_fn::coerce<T>((T1&&) t1, 0).*f)
  110. {
  111. return invoke_fn::coerce<T>((T1&&) t1, 0).*f;
  112. }
  113. template<typename F, typename... Args>
  114. CPP_PP_IIF(RANGES_CONSTEXPR_INVOKE)(CPP_PP_EXPAND, CPP_PP_EAT)(constexpr)
  115. auto operator()(F&& f, Args&&... args) const
  116. noexcept(noexcept(((F&&) f)((Args&&) args...)))
  117. -> decltype(((F&&) f)((Args&&) args...))
  118. {
  119. return ((F&&) f)((Args&&) args...);
  120. }
  121. };
  122. RANGES_INLINE_VARIABLE(invoke_fn, invoke)
  123. #ifdef RANGES_WORKAROUND_MSVC_701385
  124. /// \cond
  125. namespace detail
  126. {
  127. template<typename Void, typename Fun, typename... Args>
  128. struct _invoke_result_
  129. {};
  130. template<typename Fun, typename... Args>
  131. struct _invoke_result_<
  132. meta::void_<decltype(invoke(std::declval<Fun>(), std::declval<Args>()...))>,
  133. Fun, Args...>
  134. {
  135. using type = decltype(invoke(std::declval<Fun>(), std::declval<Args>()...));
  136. };
  137. } // namespace detail
  138. /// \endcond
  139. template<typename Fun, typename... Args>
  140. using invoke_result = detail::_invoke_result_<void, Fun, Args...>;
  141. template<typename Fun, typename... Args>
  142. using invoke_result_t = meta::_t<invoke_result<Fun, Args...>>;
  143. #else // RANGES_WORKAROUND_MSVC_701385
  144. template<typename Fun, typename... Args>
  145. using invoke_result_t =
  146. decltype(invoke(std::declval<Fun>(), std::declval<Args>()...));
  147. template<typename Fun, typename... Args>
  148. struct invoke_result : meta::defer<invoke_result_t, Fun, Args...>
  149. {};
  150. #endif // RANGES_WORKAROUND_MSVC_701385
  151. /// \cond
  152. namespace detail
  153. {
  154. template<bool IsInvocable>
  155. struct is_nothrow_invocable_impl_
  156. {
  157. template<typename Fn, typename... Args>
  158. static constexpr bool apply() noexcept
  159. {
  160. return false;
  161. }
  162. };
  163. template<>
  164. struct is_nothrow_invocable_impl_<true>
  165. {
  166. template<typename Fn, typename... Args>
  167. static constexpr bool apply() noexcept
  168. {
  169. return noexcept(invoke(std::declval<Fn>(), std::declval<Args>()...));
  170. }
  171. };
  172. } // namespace detail
  173. /// \endcond
  174. template<typename Fn, typename... Args>
  175. RANGES_INLINE_VAR constexpr bool is_invocable_v =
  176. meta::is_trait<invoke_result<Fn, Args...>>::value;
  177. template<typename Fn, typename... Args>
  178. RANGES_INLINE_VAR constexpr bool is_nothrow_invocable_v =
  179. detail::is_nothrow_invocable_impl_<is_invocable_v<Fn, Args...>>::template apply<
  180. Fn, Args...>();
  181. /// \cond
  182. template<typename Sig>
  183. struct RANGES_DEPRECATED(
  184. "ranges::result_of is deprecated. "
  185. "Please use ranges::invoke_result") result_of
  186. {};
  187. template<typename Fun, typename... Args>
  188. struct RANGES_DEPRECATED(
  189. "ranges::result_of is deprecated. "
  190. "Please use ranges::invoke_result") result_of<Fun(Args...)>
  191. : meta::defer<invoke_result_t, Fun, Args...>
  192. {};
  193. /// \endcond
  194. namespace cpp20
  195. {
  196. using ranges::invoke;
  197. using ranges::invoke_result;
  198. using ranges::invoke_result_t;
  199. using ranges::is_invocable_v;
  200. using ranges::is_nothrow_invocable_v;
  201. } // namespace cpp20
  202. /// @}
  203. } // namespace ranges
  204. RANGES_DIAGNOSTIC_POP
  205. #include <range/v3/detail/epilogue.hpp>
  206. #endif // RANGES_V3_FUNCTIONAL_INVOKE_HPP