• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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