1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_CALLABLE_WITH_HPP
12 #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_CALLABLE_WITH_HPP
13 
14 //Mark that we don't support 0 arg calls due to compiler ICE in GCC 3.4/4.0/4.1 and
15 //wrong SFINAE for GCC 4.2/4.3
16 #if defined(__GNUC__) && !defined(__clang__) && ((__GNUC__*100 + __GNUC_MINOR__*10) >= 340) && ((__GNUC__*100 + __GNUC_MINOR__*10) <= 430)
17    #define BOOST_INTRUSIVE_DETAIL_HAS_MEMBER_FUNCTION_CALLABLE_WITH_0_ARGS_UNSUPPORTED
18 #elif defined(BOOST_INTEL) && (BOOST_INTEL < 1200 )
19    #define BOOST_INTRUSIVE_DETAIL_HAS_MEMBER_FUNCTION_CALLABLE_WITH_0_ARGS_UNSUPPORTED
20 #endif
21 #include <cstddef>
22 #include <boost/move/utility_core.hpp>
23 #include <boost/move/detail/fwd_macros.hpp>
24 
25 namespace boost_intrusive_hmfcw {
26 
27 typedef char yes_type;
28 struct no_type{ char dummy[2]; };
29 
30 #if defined(BOOST_NO_CXX11_DECLTYPE)
31 
32 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
33 
34 template<class T>
35 struct make_dontcare
36 {
37    typedef dont_care type;
38 };
39 
40 #endif
41 
42 struct dont_care
43 {
44    dont_care(...);
45 };
46 
47 struct private_type
48 {
49    static private_type p;
50    private_type const &operator,(int) const;
51 };
52 
53 template<typename T>
54 no_type is_private_type(T const &);
55 yes_type is_private_type(private_type const &);
56 
57 #endif   //#if defined(BOOST_NO_CXX11_DECLTYPE)
58 
59 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
60 
61 template<typename T> struct remove_cv                    {  typedef T type;   };
62 template<typename T> struct remove_cv<const T>           {  typedef T type;   };
63 template<typename T> struct remove_cv<const volatile T>  {  typedef T type;   };
64 template<typename T> struct remove_cv<volatile T>        {  typedef T type;   };
65 
66 #endif
67 
68 }  //namespace boost_intrusive_hmfcw {
69 
70 #endif  //BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_CALLABLE_WITH_HPP
71 
72 #ifndef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME
73    #error "You MUST define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME before including this header!"
74 #endif
75 
76 #ifndef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN
77    #error "You MUST define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN before including this header!"
78 #endif
79 
80 #ifndef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX
81    #error "You MUST define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX before including this header!"
82 #endif
83 
84 #if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX < BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN
85    #error "BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX value MUST be greater or equal than BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN!"
86 #endif
87 
88 #if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX == 0
89    #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF
90 #else
91    #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF ,
92 #endif
93 
94 #ifndef  BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG
95    #error "BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG not defined!"
96 #endif
97 
98 #ifndef  BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END
99    #error "BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END not defined!"
100 #endif
101 
102 BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG
103 
104 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE)
105    //With decltype and variadic templaes, things are pretty easy
106    template<typename Fun, class ...Args>
BOOST_MOVE_CAT(has_member_function_callable_with_,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)107    struct BOOST_MOVE_CAT(has_member_function_callable_with_,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
108    {
109       template<class U>
110       static decltype(boost::move_detail::declval<U>().
111          BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(::boost::move_detail::declval<Args>()...)
112             , boost_intrusive_hmfcw::yes_type()) Test(U* f);
113       template<class U>
114       static boost_intrusive_hmfcw::no_type Test(...);
115       static const bool value = sizeof(Test<Fun>((Fun*)0)) == sizeof(boost_intrusive_hmfcw::yes_type);
116    };
117 
118 #else //defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_DECLTYPE)
119 
120    /////////////////////////////////////////////////////////
121    /////////////////////////////////////////////////////////
122    //
123    //    has_member_function_callable_with_impl_XXX
124    //    declaration, special case and 0 arg specializaton
125    //
126    /////////////////////////////////////////////////////////
127    /////////////////////////////////////////////////////////
128 
129    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
130       /////////////////////////////////////////////////////////
131       /////////////////////////////////////////////////////////
132       //
133       //    has_member_function_callable_with_impl_XXX for 1 to N arguments
134       //
135       /////////////////////////////////////////////////////////
136       /////////////////////////////////////////////////////////
137 
138       //defined(BOOST_NO_CXX11_DECLTYPE) must be true
139       template<class Fun, class ...DontCares>
140       struct FunWrapTmpl : Fun
141       {
142          using Fun::BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME;
143          boost_intrusive_hmfcw::private_type BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(DontCares...) const;
144       };
145 
146       template<typename Fun, class ...Args>
147       struct BOOST_MOVE_CAT(has_member_function_callable_with_,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun, Args...>
148       {
149          typedef FunWrapTmpl<typename boost_intrusive_hmfcw::make_dontcare<Args>::type...> FunWrap;
150 
151          static bool const value = (sizeof(boost_intrusive_hmfcw::no_type) ==
152                                     sizeof(boost_intrusive_hmfcw::is_private_type
153                                              ( (::boost::move_detail::declval< FunWrap<Fun> >().
154                                                    BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(::boost::move_detail::declval<Args>()...), 0) )
155                                           )
156                                     );
157       };
158    #else //defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
159 
160       //Preprocessor must be used to generate specializations instead of variadic templates
161 
162       template <typename Type>
163       class BOOST_MOVE_CAT(has_member_function_named_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
164       {
165          struct BaseMixin
166          {
167             void BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME();
168          };
169 
170          struct Base
171             : public boost_intrusive_hmfcw::remove_cv<Type>::type, public BaseMixin
172          {  //Declare the unneeded default constructor as some old compilers wrongly require it with is_convertible
173             Base();
174          };
175          template <typename T, T t> class Helper{};
176 
177          template <typename U>
178          static boost_intrusive_hmfcw::no_type  deduce
179             (U*, Helper<void (BaseMixin::*)(), &U::BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME>* = 0);
180          static boost_intrusive_hmfcw::yes_type deduce(...);
181 
182          public:
183          static const bool value = sizeof(boost_intrusive_hmfcw::yes_type) == sizeof(deduce((Base*)0));
184       };
185 
186       /////////////////////////////////////////////////////////
187       /////////////////////////////////////////////////////////
188       //
189       //    has_member_function_callable_with_impl_XXX specializations
190       //
191       /////////////////////////////////////////////////////////
192 
193       template<typename Fun, bool HasFunc BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF BOOST_MOVE_CAT(BOOST_MOVE_CLASSDFLT,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)>
194       struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME);
195 
196       //No BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME member specialization
197       template<typename Fun BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF BOOST_MOVE_CAT(BOOST_MOVE_CLASS,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)>
198       struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
199          <Fun, false BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF BOOST_MOVE_CAT(BOOST_MOVE_TARG,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)>
200       {
201          static const bool value = false;
202       };
203 
204       #if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN == 0
205          //0 arg specialization when BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME is present
206          #if !defined(BOOST_NO_CXX11_DECLTYPE)
207 
208             template<typename Fun>
209             struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun, true>
210             {
211                template<class U>
212                static decltype(boost::move_detail::declval<U>().BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME()
213                   , boost_intrusive_hmfcw::yes_type()) Test(U* f);
214 
215                template<class U>
216                static boost_intrusive_hmfcw::no_type Test(...);
217                static const bool value = sizeof(Test<Fun>((Fun*)0)) == sizeof(boost_intrusive_hmfcw::yes_type);
218             };
219 
220          #else //defined(BOOST_NO_CXX11_DECLTYPE)
221 
222             #if !defined(BOOST_INTRUSIVE_DETAIL_HAS_MEMBER_FUNCTION_CALLABLE_WITH_0_ARGS_UNSUPPORTED)
223 
224             template<class F, std::size_t N = sizeof(boost::move_detail::declval<F>().BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(), 0)>
225             struct BOOST_MOVE_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
226             {  boost_intrusive_hmfcw::yes_type dummy[N ? 1 : 2];   };
227 
228             template<typename Fun>
229             struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun, true>
230             {
231                template<class U> static BOOST_MOVE_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<U>
232                   Test(BOOST_MOVE_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<U>*);
233                template<class U> static boost_intrusive_hmfcw::no_type Test(...);
234                static const bool value = sizeof(Test< Fun >(0)) == sizeof(boost_intrusive_hmfcw::yes_type);
235             };
236 
237             #else //defined(BOOST_INTRUSIVE_DETAIL_HAS_MEMBER_FUNCTION_CALLABLE_WITH_0_ARGS_UNSUPPORTED)
238 
239                template<typename Fun>
240                struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun, true>
241                {//GCC [3.4-4.3) gives ICE when instantiating the 0 arg version so it is not supported.
242                   static const bool value = true;
243                };
244 
245             #endif//!defined(BOOST_INTRUSIVE_DETAIL_HAS_MEMBER_FUNCTION_CALLABLE_WITH_0_ARGS_UNSUPPORTED)
246          #endif   //!defined(BOOST_NO_CXX11_DECLTYPE)
247       #endif   //#if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN == 0
248 
249       #if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX > 0
250          //1 to N arg specialization when BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME is present
251          //Declare some unneeded default constructor as some old compilers wrongly require it with is_convertible
252          #if defined(BOOST_NO_CXX11_DECLTYPE)
253             #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATION(N)\
254             \
255             template<class Fun>\
256             struct BOOST_MOVE_CAT(FunWrap##N, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)\
257                : Fun\
258             {\
259                using Fun::BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME;\
260                BOOST_MOVE_CAT(FunWrap##N, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)();\
261                boost_intrusive_hmfcw::private_type BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME\
262                   (BOOST_MOVE_REPEAT##N(boost_intrusive_hmfcw::dont_care)) const;\
263             };\
264             \
265             template<typename Fun, BOOST_MOVE_CLASS##N>\
266             struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun, true, BOOST_MOVE_TARG##N>\
267             {\
268                static bool const value = (sizeof(boost_intrusive_hmfcw::no_type) == sizeof(boost_intrusive_hmfcw::is_private_type\
269                                                    ( (::boost::move_detail::declval\
270                                                          < BOOST_MOVE_CAT(FunWrap##N, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun> >().\
271                                                       BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(BOOST_MOVE_DECLVAL##N), 0) )\
272                                                 )\
273                                           );\
274             };\
275             //
276          #else
277             #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATION(N)\
278             template<typename Fun, BOOST_MOVE_CLASS##N>\
279             struct BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)\
280                <Fun, true, BOOST_MOVE_TARG##N>\
281             {\
282                template<class U>\
283                static decltype(boost::move_detail::declval<U>().\
284                   BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME(BOOST_MOVE_DECLVAL##N)\
285                      , boost_intrusive_hmfcw::yes_type()) Test(U* f);\
286                template<class U>\
287                static boost_intrusive_hmfcw::no_type Test(...);\
288                static const bool value = sizeof(Test<Fun>((Fun*)0)) == sizeof(boost_intrusive_hmfcw::yes_type);\
289             };\
290             //
291          #endif
292          ////////////////////////////////////
293          // Build and invoke BOOST_MOVE_ITERATE_NTOM macrofunction, note that N has to be at least 1
294          ////////////////////////////////////
295          #if BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN == 0
296             #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATE_MIN 1
297          #else
298             #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATE_MIN BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN
299          #endif
300          BOOST_MOVE_CAT
301             (BOOST_MOVE_CAT(BOOST_MOVE_CAT(BOOST_MOVE_ITERATE_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATE_MIN), TO)
302             ,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)
303                (BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATION)
304          #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATION
305          #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_ITERATE_MIN
306          ////////////////////////////////////
307          // End of BOOST_MOVE_ITERATE_NTOM
308          ////////////////////////////////////
309       #endif   //BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX > 0
310 
311       /////////////////////////////////////////////////////////
312       /////////////////////////////////////////////////////////
313       //
314       //       has_member_function_callable_with_FUNC
315       //
316       /////////////////////////////////////////////////////////
317       /////////////////////////////////////////////////////////
318 
319       //Otherwise use the preprocessor
320       template<typename Fun BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF BOOST_MOVE_CAT(BOOST_MOVE_CLASSDFLT,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)>
321       struct BOOST_MOVE_CAT(has_member_function_callable_with_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
322          : public BOOST_MOVE_CAT(has_member_function_callable_with_impl_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)
323             <Fun
324             , BOOST_MOVE_CAT(has_member_function_named_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)<Fun>::value
325             BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF BOOST_MOVE_CAT(BOOST_MOVE_TARG,BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX)>
326       {};
327    #endif   //defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
328 #endif
329 
330 BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END
331 
332 //Undef local macros
333 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_COMMA_IF
334 
335 //Undef user defined macros
336 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME
337 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN
338 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX
339 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG
340 #undef BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END
341