1 
2 // Copyright 2000 John Maddock (john@johnmaddock.co.uk)
3 // Copyright 2000 Jeremy Siek (jsiek@lsc.nd.edu)
4 // Copyright 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
5 //
6 //  Use, modification and distribution are subject to the Boost Software License,
7 //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt).
9 //
10 //  See http://www.boost.org/libs/type_traits for most recent version including documentation.
11 
12 #ifndef BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
13 #define BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
14 
15 #include <boost/type_traits/intrinsics.hpp>
16 #ifndef BOOST_IS_CONVERTIBLE
17 #include <boost/type_traits/detail/yes_no_type.hpp>
18 #include <boost/type_traits/config.hpp>
19 #include <boost/type_traits/is_array.hpp>
20 #include <boost/type_traits/ice.hpp>
21 #include <boost/type_traits/is_arithmetic.hpp>
22 #include <boost/type_traits/is_void.hpp>
23 #ifndef BOOST_NO_IS_ABSTRACT
24 #include <boost/type_traits/is_abstract.hpp>
25 #endif
26 #include <boost/type_traits/add_lvalue_reference.hpp>
27 #include <boost/type_traits/add_rvalue_reference.hpp>
28 #include <boost/type_traits/is_function.hpp>
29 
30 #if defined(__MWERKS__)
31 #include <boost/type_traits/remove_reference.hpp>
32 #endif
33 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
34 #  include <boost/utility/declval.hpp>
35 #endif
36 #endif // BOOST_IS_CONVERTIBLE
37 
38 // should be always the last #include directive
39 #include <boost/type_traits/detail/bool_trait_def.hpp>
40 
41 namespace boost {
42 
43 #ifndef BOOST_IS_CONVERTIBLE
44 
45 // is one type convertible to another?
46 //
47 // there are multiple versions of the is_convertible
48 // template, almost every compiler seems to require its
49 // own version.
50 //
51 // Thanks to Andrei Alexandrescu for the original version of the
52 // conversion detection technique!
53 //
54 
55 namespace detail {
56 
57 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
58 
59    // This is a C++11 conforming version, place this first and use it wherever possible:
60 
61 #  define BOOST_TT_CXX11_IS_CONVERTIBLE
62 
63    template <class A, class B, class C>
64    struct or_helper
65    {
66       static const bool value = (A::value || B::value || C::value);
67    };
68 
69    template<typename From, typename To, bool b = or_helper<boost::is_void<From>, boost::is_function<To>, boost::is_array<To> >::value>
70    struct is_convertible_basic_impl
71    {
72       // Nothing converts to function or array, but void converts to void:
73       static const bool value = is_void<To>::value;
74    };
75 
76    template<typename From, typename To>
77    class is_convertible_basic_impl<From, To, false>
78    {
79       typedef char one;
80       typedef int  two;
81 
82       template<typename To1>
83       static void test_aux(To1);
84 
85       template<typename From1, typename To1>
86       static decltype(test_aux<To1>(boost::declval<From1>()), one()) test(int);
87 
88       template<typename, typename>
89       static two test(...);
90 
91    public:
92       static const bool value = sizeof(test<From, To>(0)) == 1;
93    };
94 
95 #elif defined(__BORLANDC__) && (__BORLANDC__ < 0x560)
96 //
97 // special version for Borland compilers
98 // this version breaks when used for some
99 // UDT conversions:
100 //
101 template <typename From, typename To>
102 struct is_convertible_impl
103 {
104 #pragma option push -w-8074
105     // This workaround for Borland breaks the EDG C++ frontend,
106     // so we only use it for Borland.
107     template <typename T> struct checker
108     {
109         static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
110         static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(T);
111     };
112 
113     static typename add_lvalue_reference<From>::type  _m_from;
114     static bool const value = sizeof( checker<To>::_m_check(_m_from) )
115         == sizeof(::boost::type_traits::yes_type);
116 #pragma option pop
117 };
118 
119 #elif defined(__GNUC__) || defined(__BORLANDC__) && (__BORLANDC__ < 0x600)
120 // special version for gcc compiler + recent Borland versions
121 // note that this does not pass UDT's through (...)
122 
123 struct any_conversion
124 {
125     template <typename T> any_conversion(const volatile T&);
126     template <typename T> any_conversion(const T&);
127     template <typename T> any_conversion(volatile T&);
128     template <typename T> any_conversion(T&);
129 };
130 
131 template <typename T> struct checker
132 {
133     static boost::type_traits::no_type _m_check(any_conversion ...);
134     static boost::type_traits::yes_type _m_check(T, int);
135 };
136 
137 template <typename From, typename To>
138 struct is_convertible_basic_impl
139 {
140     typedef typename add_lvalue_reference<From>::type lvalue_type;
141     typedef typename add_rvalue_reference<From>::type rvalue_type;
142     static lvalue_type _m_from;
143 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)))
144     static bool const value =
145         sizeof( boost::detail::checker<To>::_m_check(static_cast<rvalue_type>(_m_from), 0) )
146         == sizeof(::boost::type_traits::yes_type);
147 #else
148     static bool const value =
149         sizeof( boost::detail::checker<To>::_m_check(_m_from, 0) )
150         == sizeof(::boost::type_traits::yes_type);
151 #endif
152 };
153 
154 #elif (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 245) && !defined(__ICL)) \
155       || defined(__IBMCPP__) || defined(__HP_aCC)
156 //
157 // This is *almost* an ideal world implementation as it doesn't rely
158 // on undefined behaviour by passing UDT's through (...).
159 // Unfortunately it doesn't quite pass all the tests for most compilers (sigh...)
160 // Enable this for your compiler if is_convertible_test.cpp will compile it...
161 //
162 // Note we do not enable this for VC7.1, because even though it passes all the
163 // type_traits tests it is known to cause problems when instantiation occurs
164 // deep within the instantiation tree :-(
165 //
166 struct any_conversion
167 {
168     template <typename T> any_conversion(const volatile T&);
169     template <typename T> any_conversion(const T&);
170     template <typename T> any_conversion(volatile T&);
171     // we need this constructor to catch references to functions
172     // (which can not be cv-qualified):
173     template <typename T> any_conversion(T&);
174 };
175 
176 template <typename From, typename To>
177 struct is_convertible_basic_impl
178 {
179     static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
180     static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
181     typedef typename add_lvalue_reference<From>::type lvalue_type;
182     typedef typename add_rvalue_reference<From>::type rvalue_type;
183     static lvalue_type _m_from;
184 
185 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
186     BOOST_STATIC_CONSTANT(bool, value =
187         sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
188         );
189 #else
190     BOOST_STATIC_CONSTANT(bool, value =
191         sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
192         );
193 #endif
194 };
195 
196 #elif defined(__DMC__)
197 
198 struct any_conversion
199 {
200     template <typename T> any_conversion(const volatile T&);
201     template <typename T> any_conversion(const T&);
202     template <typename T> any_conversion(volatile T&);
203     // we need this constructor to catch references to functions
204     // (which can not be cv-qualified):
205     template <typename T> any_conversion(T&);
206 };
207 
208 template <typename From, typename To>
209 struct is_convertible_basic_impl
210 {
211     // Using '...' doesn't always work on Digital Mars. This version seems to.
212     template <class T>
213     static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion,  float, T);
214     static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int, int);
215     typedef typename add_lvalue_reference<From>::type lvalue_type;
216     typedef typename add_rvalue_reference<From>::type rvalue_type;
217     static lvalue_type _m_from;
218 
219     // Static constants sometime cause the conversion of _m_from to To to be
220     // called. This doesn't happen with an enum.
221 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
222     enum { value =
223         sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0, 0) ) == sizeof(::boost::type_traits::yes_type)
224         };
225 #else
226     enum { value =
227         sizeof( _m_check(_m_from, 0, 0) ) == sizeof(::boost::type_traits::yes_type)
228         };
229 #endif
230 };
231 
232 #elif defined(__MWERKS__)
233 //
234 // CW works with the technique implemented above for EDG, except when From
235 // is a function type (or a reference to such a type), in which case
236 // any_conversion won't be accepted as a valid conversion. We detect this
237 // exceptional situation and channel it through an alternative algorithm.
238 //
239 
240 template <typename From, typename To,bool FromIsFunctionRef>
241 struct is_convertible_basic_impl_aux;
242 
243 struct any_conversion
244 {
245     template <typename T> any_conversion(const volatile T&);
246     template <typename T> any_conversion(const T&);
247     template <typename T> any_conversion(volatile T&);
248     template <typename T> any_conversion(T&);
249 };
250 
251 template <typename From, typename To>
252 struct is_convertible_basic_impl_aux<From,To,false /*FromIsFunctionRef*/>
253 {
254     static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
255     static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
256     typedef typename add_lvalue_reference<From>::type lvalue_type;
257     typedef typename add_rvalue_reference<From>::type rvalue_type;
258     static lvalue_type _m_from;
259 
260 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
261     BOOST_STATIC_CONSTANT(bool, value =
262         sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
263         );
264 #else
265     BOOST_STATIC_CONSTANT(bool, value =
266         sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
267         );
268 #endif
269 };
270 
271 template <typename From, typename To>
272 struct is_convertible_basic_impl_aux<From,To,true /*FromIsFunctionRef*/>
273 {
274     static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
275     static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
276     typedef typename add_lvalue_reference<From>::type lvalue_type;
277     typedef typename add_rvalue_reference<From>::type rvalue_type;
278     static lvalue_type _m_from;
279 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
280     BOOST_STATIC_CONSTANT(bool, value =
281         sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
282         );
283 #else
284     BOOST_STATIC_CONSTANT(bool, value =
285         sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
286         );
287 #endif
288 };
289 
290 template <typename From, typename To>
291 struct is_convertible_basic_impl:
292   is_convertible_basic_impl_aux<
293     From,To,
294     ::boost::is_function<typename ::boost::remove_reference<From>::type>::value
295   >
296 {};
297 
298 #else
299 //
300 // This version seems to work pretty well for a wide spectrum of compilers,
301 // however it does rely on undefined behaviour by passing UDT's through (...).
302 //
303 template <typename From, typename To>
304 struct is_convertible_basic_impl
305 {
306     static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
307     static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
308     typedef typename add_lvalue_reference<From>::type lvalue_type;
309     typedef typename add_rvalue_reference<From>::type rvalue_type;
310     static lvalue_type _m_from;
311 #ifdef BOOST_MSVC
312 #pragma warning(push)
313 #pragma warning(disable:4244)
314 #if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000)
315 #pragma warning(disable:6334)
316 #endif
317 #endif
318 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
319     BOOST_STATIC_CONSTANT(bool, value =
320         sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
321         );
322 #else
323     BOOST_STATIC_CONSTANT(bool, value =
324         sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
325         );
326 #endif
327 #ifdef BOOST_MSVC
328 #pragma warning(pop)
329 #endif
330 };
331 
332 #endif // is_convertible_impl
333 
334 #if defined(__DMC__)
335 // As before, a static constant sometimes causes errors on Digital Mars.
336 template <typename From, typename To>
337 struct is_convertible_impl
338 {
339     enum { value =
340         (::boost::type_traits::ice_and<
341             ::boost::type_traits::ice_or<
342                ::boost::detail::is_convertible_basic_impl<From,To>::value,
343                ::boost::is_void<To>::value
344             >::value,
345             ::boost::type_traits::ice_not<
346                ::boost::is_array<To>::value
347             >::value,
348             ::boost::type_traits::ice_not<
349                ::boost::is_function<To>::value
350             >::value
351         >::value) };
352 };
353 #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551
354 template <typename From, typename To>
355 struct is_convertible_impl
356 {
357     BOOST_STATIC_CONSTANT(bool, value =
358         (::boost::type_traits::ice_and<
359             ::boost::type_traits::ice_or<
360                ::boost::detail::is_convertible_basic_impl<From,To>::value,
361                ::boost::is_void<To>::value
362             >::value,
363             ::boost::type_traits::ice_not<
364                ::boost::is_array<To>::value
365             >::value,
366             ::boost::type_traits::ice_not<
367                ::boost::is_function<To>::value
368             >::value
369         >::value)
370         );
371 };
372 #endif
373 
374 template <bool trivial1, bool trivial2, bool abstract_target>
375 struct is_convertible_impl_select
376 {
377    template <class From, class To>
378    struct rebind
379    {
380       typedef is_convertible_impl<From, To> type;
381    };
382 };
383 
384 template <>
385 struct is_convertible_impl_select<true, true, false>
386 {
387    template <class From, class To>
388    struct rebind
389    {
390       typedef true_type type;
391    };
392 };
393 
394 template <>
395 struct is_convertible_impl_select<false, false, true>
396 {
397    template <class From, class To>
398    struct rebind
399    {
400       typedef false_type type;
401    };
402 };
403 
404 template <>
405 struct is_convertible_impl_select<true, false, true>
406 {
407    template <class From, class To>
408    struct rebind
409    {
410       typedef false_type type;
411    };
412 };
413 
414 template <typename From, typename To>
415 struct is_convertible_impl_dispatch_base
416 {
417 #if !BOOST_WORKAROUND(__HP_aCC, < 60700)
418    typedef is_convertible_impl_select<
419       ::boost::is_arithmetic<From>::value,
420       ::boost::is_arithmetic<To>::value,
421 #if !defined(BOOST_NO_IS_ABSTRACT) && !defined(BOOST_TT_CXX11_IS_CONVERTIBLE)
422       // We need to filter out abstract types, only if we don't have a strictly conforming C++11 version:
423       ::boost::is_abstract<To>::value
424 #else
425       false
426 #endif
427    > selector;
428 #else
429    typedef is_convertible_impl_select<false, false, false> selector;
430 #endif
431    typedef typename selector::template rebind<From, To> isc_binder;
432    typedef typename isc_binder::type type;
433 };
434 
435 template <typename From, typename To>
436 struct is_convertible_impl_dispatch
437    : public is_convertible_impl_dispatch_base<From, To>::type
438 {};
439 
440 //
441 // Now add the full and partial specialisations
442 // for void types, these are common to all the
443 // implementation above:
444 //
445 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
446 #   define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \
447     BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2,value) \
448     BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const,value) \
449     BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 volatile,value) \
450     BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const volatile,value) \
451     /**/
452 
453 #   define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(trait,spec1,spec2,value) \
454     TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \
455     TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const,spec2,value) \
456     TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 volatile,spec2,value) \
457     TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const volatile,spec2,value) \
458     /**/
459 
460     TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(is_convertible,void,void,true)
461 
462 #   undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2
463 #   undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1
464 
465 #else
466     BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(is_convertible,void,void,true)
467 #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS
468 
469 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void,To,false)
470 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void,false)
471 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
472 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const,To,false)
473 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void volatile,To,false)
474 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const volatile,To,false)
475 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const,false)
476 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void volatile,false)
477 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const volatile,false)
478 #endif
479 
480 } // namespace detail
481 
482 BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,(::boost::detail::is_convertible_impl_dispatch<From,To>::value))
483 
484 #else
485 
486 BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,BOOST_IS_CONVERTIBLE(From,To))
487 
488 #endif
489 
490 } // namespace boost
491 
492 #include <boost/type_traits/detail/bool_trait_undef.hpp>
493 
494 #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
495