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.

invoke.hpp 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. RANGES_DIAGNOSTIC_PUSH
  23. RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT
  24. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  25. #ifndef RANGES_CONSTEXPR_INVOKE
  26. #ifdef RANGES_WORKAROUND_CLANG_23135
  27. #define RANGES_CONSTEXPR_INVOKE 0
  28. #else
  29. #define RANGES_CONSTEXPR_INVOKE 1
  30. #endif
  31. #endif
  32. namespace ranges
  33. {
  34. /// \addtogroup group-functional
  35. /// @{
  36. /// \cond
  37. namespace detail
  38. {
  39. template<typename U>
  40. U & can_reference_(U &&);
  41. // clang-format off
  42. CPP_def
  43. (
  44. template(typename T)
  45. concept dereferenceable_,
  46. requires (T &&t)
  47. (
  48. detail::can_reference_(*static_cast<T &&>(t))
  49. )
  50. );
  51. // clang-format on
  52. template<class T>
  53. RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v =
  54. meta::is<T, reference_wrapper>::value ||
  55. meta::is<T, std::reference_wrapper>::value;
  56. } // namespace detail
  57. /// \endcond
  58. template<class T>
  59. RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v =
  60. detail::is_reference_wrapper_v<detail::decay_t<T>>;
  61. template<typename T>
  62. using is_reference_wrapper = meta::bool_<is_reference_wrapper_v<T>>;
  63. template<typename T>
  64. using is_reference_wrapper_t RANGES_DEPRECATED(
  65. "is_reference_wrapper_t is deprecated.") = meta::_t<is_reference_wrapper<T>>;
  66. struct invoke_fn
  67. {
  68. private:
  69. template<class, class T1>
  70. constexpr static decltype(auto) CPP_fun(coerce)(T1 && t1, long)( //
  71. noexcept(noexcept(*static_cast<T1 &&>(t1))) //
  72. requires detail::dereferenceable_<T1>)
  73. {
  74. return *static_cast<T1 &&>(t1);
  75. }
  76. template<class T, class T1>
  77. constexpr static auto coerce(T1 && t1, int) noexcept -> CPP_ret(T1 &&)( //
  78. requires derived_from<detail::decay_t<T1>, T>)
  79. {
  80. return static_cast<T1 &&>(t1);
  81. }
  82. template<class, class T1>
  83. constexpr static decltype(auto) CPP_fun(coerce)(T1 && t1, int)(
  84. noexcept(true) //
  85. requires detail::is_reference_wrapper_v<detail::decay_t<T1>>)
  86. {
  87. return static_cast<T1 &&>(t1).get();
  88. }
  89. public:
  90. // clang-format off
  91. template<class F, class T, class T1, class... Args>
  92. constexpr auto CPP_auto_fun(operator())(F T::*f, T1&& t1, Args&&... args)(const)
  93. (
  94. return (invoke_fn::coerce<T>(static_cast<T1&&>(t1), 0).*f)
  95. (static_cast<Args&&>(args)...)
  96. )
  97. template<class D, class T, class T1>
  98. constexpr auto CPP_auto_fun(operator())(D T::*f, T1&& t1)(const)
  99. (
  100. return invoke_fn::coerce<T>(static_cast<T1&&>(t1), 0).*f
  101. )
  102. template<class F, class... Args>
  103. CPP_PP_IIF(RANGES_CONSTEXPR_INVOKE)(CPP_PP_EXPAND, CPP_PP_EAT)(constexpr)
  104. auto CPP_auto_fun(operator())(F&& f, Args&&... args)(const)
  105. (
  106. return static_cast<F&&>(f)(static_cast<Args&&>(args)...)
  107. )
  108. // clang-format on
  109. };
  110. RANGES_INLINE_VARIABLE(invoke_fn, invoke)
  111. #ifdef RANGES_WORKAROUND_MSVC_701385
  112. /// \cond
  113. namespace detail
  114. {
  115. template<typename Void, typename Fun, typename... Args>
  116. struct _invoke_result_
  117. {};
  118. template<typename Fun, typename... Args>
  119. struct _invoke_result_<
  120. meta::void_<decltype(invoke(std::declval<Fun>(), std::declval<Args>()...))>,
  121. Fun, Args...>
  122. {
  123. using type = decltype(invoke(std::declval<Fun>(), std::declval<Args>()...));
  124. };
  125. } // namespace detail
  126. /// \endcond
  127. template<typename Fun, typename... Args>
  128. using invoke_result = detail::_invoke_result_<void, Fun, Args...>;
  129. template<typename Fun, typename... Args>
  130. using invoke_result_t = meta::_t<invoke_result<Fun, Args...>>;
  131. #else // RANGES_WORKAROUND_MSVC_701385
  132. template<typename Fun, typename... Args>
  133. using invoke_result_t =
  134. decltype(invoke(std::declval<Fun>(), std::declval<Args>()...));
  135. template<typename Fun, typename... Args>
  136. struct invoke_result : meta::defer<invoke_result_t, Fun, Args...>
  137. {};
  138. #endif // RANGES_WORKAROUND_MSVC_701385
  139. /// \cond
  140. namespace detail
  141. {
  142. template<bool IsInvocable>
  143. struct is_nothrow_invocable_impl_
  144. {
  145. template<typename Fn, typename... Args>
  146. static constexpr bool apply() noexcept
  147. {
  148. return false;
  149. }
  150. };
  151. template<>
  152. struct is_nothrow_invocable_impl_<true>
  153. {
  154. template<typename Fn, typename... Args>
  155. static constexpr bool apply() noexcept
  156. {
  157. return noexcept(invoke(std::declval<Fn>(), std::declval<Args>()...));
  158. }
  159. };
  160. } // namespace detail
  161. /// \endcond
  162. template<typename Fn, typename... Args>
  163. RANGES_INLINE_VAR constexpr bool is_invocable_v =
  164. meta::is_trait<invoke_result<Fn, Args...>>::value;
  165. template<typename Fn, typename... Args>
  166. RANGES_INLINE_VAR constexpr bool is_nothrow_invocable_v =
  167. detail::is_nothrow_invocable_impl_<is_invocable_v<Fn, Args...>>::template apply<
  168. Fn, Args...>();
  169. /// \cond
  170. template<typename Sig>
  171. struct RANGES_DEPRECATED(
  172. "ranges::result_of is deprecated. "
  173. "Please use ranges::invoke_result") result_of
  174. {};
  175. template<typename Fun, typename... Args>
  176. struct RANGES_DEPRECATED(
  177. "ranges::result_of is deprecated. "
  178. "Please use ranges::invoke_result") result_of<Fun(Args...)>
  179. : meta::defer<invoke_result_t, Fun, Args...>
  180. {};
  181. /// \endcond
  182. namespace cpp20
  183. {
  184. using ranges::invoke;
  185. using ranges::invoke_result;
  186. using ranges::invoke_result_t;
  187. using ranges::is_invocable_v;
  188. using ranges::is_nothrow_invocable_v;
  189. } // namespace cpp20
  190. /// @}
  191. } // namespace ranges
  192. RANGES_DIAGNOSTIC_POP
  193. #endif // RANGES_V3_FUNCTIONAL_INVOKE_HPP