is_callable.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright (c) 2009-2020 Vladimir Batov.
  2. // Use, modification and distribution are subject to the Boost Software License,
  3. // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
  4. #ifndef BOOST_CONVERT_IS_CALLABLE_HPP
  5. #define BOOST_CONVERT_IS_CALLABLE_HPP
  6. #include <boost/convert/detail/has_member.hpp>
  7. namespace boost { namespace cnv { namespace detail
  8. {
  9. using yes_type = ::boost::type_traits::yes_type;
  10. using no_type = ::boost::type_traits:: no_type;
  11. struct not_found {};
  12. struct void_return_substitute {};
  13. // The overloaded comma operator only kicks in for U != void essentially short-circuiting
  14. // itself ineffective. Otherwise, when U=void, the standard op,() kicks in and returns
  15. // 'void_return_substitute'.
  16. template<typename U> U const& operator, (U const&, void_return_substitute);
  17. template<typename U> U& operator, (U&, void_return_substitute);
  18. template <typename src, typename dst> struct match_const { using type = dst; };
  19. template <typename src, typename dst> struct match_const<src const, dst> { using type = dst const; };
  20. template<typename T, typename return_type>
  21. struct redirect
  22. {
  23. static no_type test (...);
  24. static yes_type test (return_type);
  25. };
  26. template<typename T>
  27. struct redirect<T, void>
  28. {
  29. static yes_type test (...);
  30. static no_type test (not_found);
  31. };
  32. }}}
  33. // No-args case needs to be implemented differently and has not been implemented yet.
  34. // template <typename R>
  35. // struct check<true, R ()>
  36. // C1. Need to find some unique/ugly names so that they do not clash if this macro is
  37. // used inside some other template class;
  38. // C2. Body of the function is not actually used anywhere.
  39. // However, Intel C++ compiler treats it as an error. So, we provide the body.
  40. #define BOOST_DECLARE_IS_CALLABLE(__trait_name__, __member_name__) \
  41. \
  42. template <typename __boost_is_callable_T__, typename __boost_is_callable_signature__> \
  43. class __trait_name__ \
  44. { \
  45. using class_type = __boost_is_callable_T__; /*C1*/ \
  46. using signature = __boost_is_callable_signature__; /*C1*/ \
  47. using not_found = boost::cnv::detail::not_found; \
  48. \
  49. BOOST_DECLARE_HAS_MEMBER(has_member, __member_name__); \
  50. \
  51. struct mixin : class_type \
  52. { \
  53. using class_type::__member_name__; \
  54. not_found __member_name__(...) const { return not_found(); /*C2*/} \
  55. }; \
  56. using mixin_ptr = typename boost::cnv::detail::match_const<class_type, mixin>::type*; \
  57. \
  58. template <bool has, typename F> struct check { static bool const value = false; }; \
  59. \
  60. template <typename Arg1, typename R> \
  61. struct check<true, R (Arg1)> \
  62. { \
  63. using a1 = typename boost::decay<Arg1>::type*; \
  64. \
  65. static bool BOOST_CONSTEXPR_OR_CONST value = \
  66. sizeof(boost::type_traits::yes_type) == \
  67. sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
  68. (mixin_ptr(0)->__member_name__(*a1(0)), \
  69. boost::cnv::detail::void_return_substitute()))); \
  70. }; \
  71. template <typename Arg1, typename Arg2, typename R> \
  72. struct check<true, R (Arg1, Arg2)> \
  73. { \
  74. using a1 = typename boost::decay<Arg1>::type*; \
  75. using a2 = typename boost::decay<Arg2>::type*; \
  76. \
  77. static bool BOOST_CONSTEXPR_OR_CONST value = \
  78. sizeof(boost::type_traits::yes_type) == \
  79. sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
  80. (mixin_ptr(0)->__member_name__(*a1(0), *a2(0)), \
  81. boost::cnv::detail::void_return_substitute()))); \
  82. }; \
  83. \
  84. public: \
  85. \
  86. /* Check the existence of __member_name__ first, then the signature. */ \
  87. static bool BOOST_CONSTEXPR_OR_CONST value = check<has_member<class_type>::value, signature>::value; \
  88. }
  89. #endif // BOOST_CONVERT_IS_CALLABLE_HPP