is_invocable_impl.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*!
  2. @file
  3. @Copyright Barrett Adair 2015-2017
  4. Distributed under the Boost Software License, Version 1.0.
  5. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  6. */
  7. #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP
  8. #define BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP
  9. #include <boost/callable_traits/detail/config.hpp>
  10. #include <boost/callable_traits/detail/forward_declarations.hpp>
  11. #include <boost/callable_traits/detail/utility.hpp>
  12. #include <type_traits>
  13. #include <utility>
  14. namespace boost { namespace callable_traits { namespace detail {
  15. template<typename T>
  16. struct can_dereference_t
  17. {
  18. template<typename>
  19. struct check {};
  20. template<typename U>
  21. static std::int8_t test(
  22. check<typename std::remove_reference<decltype(*std::declval<U>())>::type>*
  23. );
  24. template<typename>
  25. static std::int16_t test(...);
  26. static constexpr const bool value =
  27. sizeof(test<T>(nullptr)) == sizeof(std::int8_t);
  28. };
  29. //returns std::true_type for pointers and smart pointers
  30. template<typename T>
  31. using can_dereference = std::integral_constant<bool,
  32. can_dereference_t<T>::value>;
  33. template<typename T, typename = std::true_type>
  34. struct generalize_t {
  35. using type = T;
  36. };
  37. template<typename T>
  38. struct generalize_t<T, std::integral_constant<bool,
  39. can_dereference<T>::value && !is_reference_wrapper<T>::value
  40. >>{
  41. using type = decltype(*std::declval<T>());
  42. };
  43. template<typename T>
  44. struct generalize_t<T, is_reference_wrapper<T>> {
  45. using type = decltype(std::declval<T>().get());
  46. };
  47. // When T is a pointer, generalize<T> is the resulting type of the
  48. // pointer dereferenced. When T is an std::reference_wrapper, generalize<T>
  49. // is the underlying reference type. Otherwise, generalize<T> is T.
  50. template<typename T>
  51. using generalize = typename generalize_t<T>::type;
  52. // handles the member pointer rules of INVOKE
  53. template<typename Base, typename T,
  54. typename IsBaseOf = std::is_base_of<Base, shallow_decay<T>>,
  55. typename IsSame = std::is_same<Base, shallow_decay<T>>>
  56. using generalize_if_dissimilar = typename std::conditional<
  57. IsBaseOf::value || IsSame::value, T, generalize<T>>::type;
  58. template<typename Traits, bool = Traits::is_const_member::value
  59. || Traits::is_volatile_member::value
  60. || Traits::is_lvalue_reference_member::value
  61. || Traits::is_rvalue_reference_member::value>
  62. struct test_invoke {
  63. template<typename... Rgs,
  64. typename U = typename Traits::type>
  65. auto operator()(int, Rgs&&... rgs) const ->
  66. success<decltype(std::declval<U>()(static_cast<Rgs&&>(rgs)...))>;
  67. auto operator()(long, ...) const -> substitution_failure;
  68. };
  69. template<typename F>
  70. struct test_invoke<function<F>, true /*abominable*/> {
  71. auto operator()(...) const -> substitution_failure;
  72. };
  73. template<typename Pmf, bool Ignored>
  74. struct test_invoke<pmf<Pmf>, Ignored> {
  75. using class_t = typename pmf<Pmf>::class_type;
  76. template<typename U, typename... Rgs,
  77. typename Obj = generalize_if_dissimilar<class_t, U&&>>
  78. auto operator()(int, U&& u, Rgs&&... rgs) const ->
  79. success<decltype((std::declval<Obj>().*std::declval<Pmf>())(static_cast<Rgs&&>(rgs)...))>;
  80. auto operator()(long, ...) const -> substitution_failure;
  81. };
  82. template<typename Pmd, bool Ignored>
  83. struct test_invoke<pmd<Pmd>, Ignored> {
  84. using class_t = typename pmd<Pmd>::class_type;
  85. template<typename U,
  86. typename Obj = generalize_if_dissimilar<class_t, U&&>>
  87. auto operator()(int, U&& u) const ->
  88. success<decltype(std::declval<Obj>().*std::declval<Pmd>())>;
  89. auto operator()(long, ...) const -> substitution_failure;
  90. };
  91. template<typename T, typename... Args>
  92. struct is_invocable_impl {
  93. using traits = detail::traits<T>;
  94. using test = detail::test_invoke<traits>;
  95. using result = decltype(test{}(0, ::std::declval<Args>()...));
  96. using type = std::integral_constant<bool, result::value>;
  97. };
  98. template<typename... Args>
  99. struct is_invocable_impl<void, Args...> {
  100. using type = std::false_type;
  101. };
  102. template<typename IsInvocable, typename Ret, typename T, typename... Args>
  103. struct is_invocable_r_impl {
  104. using traits = detail::traits<T>;
  105. using test = detail::test_invoke<traits>;
  106. using result = decltype(test{}(0, ::std::declval<Args>()...));
  107. using type = std::integral_constant<bool,
  108. std::is_convertible<typename result::_::type, Ret>::value
  109. || std::is_same<Ret, void>::value>;
  110. };
  111. template<typename Ret, typename T, typename... Args>
  112. struct is_invocable_r_impl<std::false_type, Ret, T, Args...> {
  113. using type = std::false_type;
  114. };
  115. }}} // namespace boost::callable_traits::detail
  116. #endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP