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