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)
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).
10 // See http://www.boost.org/libs/type_traits for most recent version including documentation.
12 #ifndef BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
13 #define BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
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>
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>
30 #if defined(__MWERKS__)
31 #include <boost/type_traits/remove_reference.hpp>
34 #endif // BOOST_IS_CONVERTIBLE
36 // should be always the last #include directive
37 #include <boost/type_traits/detail/bool_trait_def.hpp>
41 #ifndef BOOST_IS_CONVERTIBLE
43 // is one type convertible to another?
45 // there are multiple versions of the is_convertible
46 // template, almost every compiler seems to require its
49 // Thanks to Andrei Alexandrescu for the original version of the
50 // conversion detection technique!
55 // MS specific version:
57 #if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
59 // This workaround is necessary to handle when From is void
60 // which is normally taken care of by the partial specialization
61 // of the is_convertible typename.
62 using ::boost::type_traits::yes_type;
63 using ::boost::type_traits::no_type;
65 template< typename From >
66 struct does_conversion_exist
68 template< typename To > struct result_
70 static no_type BOOST_TT_DECL _m_check(...);
71 static yes_type BOOST_TT_DECL _m_check(To);
72 static typename add_lvalue_reference<From>::type _m_from;
73 enum { value = sizeof( _m_check(_m_from) ) == sizeof(yes_type) };
78 struct does_conversion_exist<void>
80 template< typename To > struct result_
82 enum { value = ::boost::is_void<To>::value };
86 template <typename From, typename To>
87 struct is_convertible_basic_impl
88 : public does_conversion_exist<From>::template result_<To>
92 #elif defined(__BORLANDC__) && (__BORLANDC__ < 0x560)
94 // special version for Borland compilers
95 // this version breaks when used for some
98 template <typename From, typename To>
99 struct is_convertible_impl
101 #pragma option push -w-8074
102 // This workaround for Borland breaks the EDG C++ frontend,
103 // so we only use it for Borland.
104 template <typename T> struct checker
106 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
107 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(T);
110 static typename add_lvalue_reference<From>::type _m_from;
111 static bool const value = sizeof( checker<To>::_m_check(_m_from) )
112 == sizeof(::boost::type_traits::yes_type);
116 #elif defined(__GNUC__) || defined(__BORLANDC__) && (__BORLANDC__ < 0x600)
117 // special version for gcc compiler + recent Borland versions
118 // note that this does not pass UDT's through (...)
120 struct any_conversion
122 template <typename T> any_conversion(const volatile T&);
123 template <typename T> any_conversion(const T&);
124 template <typename T> any_conversion(volatile T&);
125 template <typename T> any_conversion(T&);
128 template <typename T> struct checker
130 static boost::type_traits::no_type _m_check(any_conversion ...);
131 static boost::type_traits::yes_type _m_check(T, int);
134 template <typename From, typename To>
135 struct is_convertible_basic_impl
137 typedef typename add_lvalue_reference<From>::type lvalue_type;
138 typedef typename add_rvalue_reference<From>::type rvalue_type;
139 static lvalue_type _m_from;
140 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)))
141 static bool const value =
142 sizeof( boost::detail::checker<To>::_m_check(static_cast<rvalue_type>(_m_from), 0) )
143 == sizeof(::boost::type_traits::yes_type);
145 static bool const value =
146 sizeof( boost::detail::checker<To>::_m_check(_m_from, 0) )
147 == sizeof(::boost::type_traits::yes_type);
151 #elif (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 245) && !defined(__ICL)) \
152 || defined(__IBMCPP__) || defined(__HP_aCC)
154 // This is *almost* an ideal world implementation as it doesn't rely
155 // on undefined behaviour by passing UDT's through (...).
156 // Unfortunately it doesn't quite pass all the tests for most compilers (sigh...)
157 // Enable this for your compiler if is_convertible_test.cpp will compile it...
159 // Note we do not enable this for VC7.1, because even though it passes all the
160 // type_traits tests it is known to cause problems when instantiation occurs
161 // deep within the instantiation tree :-(
163 struct any_conversion
165 template <typename T> any_conversion(const volatile T&);
166 template <typename T> any_conversion(const T&);
167 template <typename T> any_conversion(volatile T&);
168 // we need this constructor to catch references to functions
169 // (which can not be cv-qualified):
170 template <typename T> any_conversion(T&);
173 template <typename From, typename To>
174 struct is_convertible_basic_impl
176 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
177 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
178 typedef typename add_lvalue_reference<From>::type lvalue_type;
179 typedef typename add_rvalue_reference<From>::type rvalue_type;
180 static lvalue_type _m_from;
182 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
183 BOOST_STATIC_CONSTANT(bool, value =
184 sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
187 BOOST_STATIC_CONSTANT(bool, value =
188 sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
193 #elif defined(__DMC__)
195 struct any_conversion
197 template <typename T> any_conversion(const volatile T&);
198 template <typename T> any_conversion(const T&);
199 template <typename T> any_conversion(volatile T&);
200 // we need this constructor to catch references to functions
201 // (which can not be cv-qualified):
202 template <typename T> any_conversion(T&);
205 template <typename From, typename To>
206 struct is_convertible_basic_impl
208 // Using '...' doesn't always work on Digital Mars. This version seems to.
210 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion, float, T);
211 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int, int);
212 typedef typename add_lvalue_reference<From>::type lvalue_type;
213 typedef typename add_rvalue_reference<From>::type rvalue_type;
214 static lvalue_type _m_from;
216 // Static constants sometime cause the conversion of _m_from to To to be
217 // called. This doesn't happen with an enum.
218 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
220 sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0, 0) ) == sizeof(::boost::type_traits::yes_type)
224 sizeof( _m_check(_m_from, 0, 0) ) == sizeof(::boost::type_traits::yes_type)
229 #elif defined(__MWERKS__)
231 // CW works with the technique implemented above for EDG, except when From
232 // is a function type (or a reference to such a type), in which case
233 // any_conversion won't be accepted as a valid conversion. We detect this
234 // exceptional situation and channel it through an alternative algorithm.
237 template <typename From, typename To,bool FromIsFunctionRef>
238 struct is_convertible_basic_impl_aux;
240 struct any_conversion
242 template <typename T> any_conversion(const volatile T&);
243 template <typename T> any_conversion(const T&);
244 template <typename T> any_conversion(volatile T&);
245 template <typename T> any_conversion(T&);
248 template <typename From, typename To>
249 struct is_convertible_basic_impl_aux<From,To,false /*FromIsFunctionRef*/>
251 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
252 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
253 typedef typename add_lvalue_reference<From>::type lvalue_type;
254 typedef typename add_rvalue_reference<From>::type rvalue_type;
255 static lvalue_type _m_from;
257 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
258 BOOST_STATIC_CONSTANT(bool, value =
259 sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
262 BOOST_STATIC_CONSTANT(bool, value =
263 sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
268 template <typename From, typename To>
269 struct is_convertible_basic_impl_aux<From,To,true /*FromIsFunctionRef*/>
271 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
272 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
273 typedef typename add_lvalue_reference<From>::type lvalue_type;
274 typedef typename add_rvalue_reference<From>::type rvalue_type;
275 static lvalue_type _m_from;
276 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
277 BOOST_STATIC_CONSTANT(bool, value =
278 sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
281 BOOST_STATIC_CONSTANT(bool, value =
282 sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
287 template <typename From, typename To>
288 struct is_convertible_basic_impl:
289 is_convertible_basic_impl_aux<
291 ::boost::is_function<typename ::boost::remove_reference<From>::type>::value
297 // This version seems to work pretty well for a wide spectrum of compilers,
298 // however it does rely on undefined behaviour by passing UDT's through (...).
300 template <typename From, typename To>
301 struct is_convertible_basic_impl
303 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
304 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
305 typedef typename add_lvalue_reference<From>::type lvalue_type;
306 typedef typename add_rvalue_reference<From>::type rvalue_type;
307 static lvalue_type _m_from;
309 #pragma warning(push)
310 #pragma warning(disable:4244)
311 #if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000)
312 #pragma warning(disable:6334)
315 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
316 BOOST_STATIC_CONSTANT(bool, value =
317 sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
320 BOOST_STATIC_CONSTANT(bool, value =
321 sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
329 #endif // is_convertible_impl
332 // As before, a static constant sometimes causes errors on Digital Mars.
333 template <typename From, typename To>
334 struct is_convertible_impl
337 (::boost::type_traits::ice_and<
338 ::boost::type_traits::ice_or<
339 ::boost::detail::is_convertible_basic_impl<From,To>::value,
340 ::boost::is_void<To>::value
342 ::boost::type_traits::ice_not<
343 ::boost::is_array<To>::value
345 ::boost::type_traits::ice_not<
346 ::boost::is_function<To>::value
350 #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551
351 template <typename From, typename To>
352 struct is_convertible_impl
354 BOOST_STATIC_CONSTANT(bool, value =
355 (::boost::type_traits::ice_and<
356 ::boost::type_traits::ice_or<
357 ::boost::detail::is_convertible_basic_impl<From,To>::value,
358 ::boost::is_void<To>::value
360 ::boost::type_traits::ice_not<
361 ::boost::is_array<To>::value
363 ::boost::type_traits::ice_not<
364 ::boost::is_function<To>::value
371 template <bool trivial1, bool trivial2, bool abstract_target>
372 struct is_convertible_impl_select
374 template <class From, class To>
377 typedef is_convertible_impl<From, To> type;
382 struct is_convertible_impl_select<true, true, false>
384 template <class From, class To>
387 typedef true_type type;
392 struct is_convertible_impl_select<false, false, true>
394 template <class From, class To>
397 typedef false_type type;
402 struct is_convertible_impl_select<true, false, true>
404 template <class From, class To>
407 typedef false_type type;
411 template <typename From, typename To>
412 struct is_convertible_impl_dispatch_base
414 #if !BOOST_WORKAROUND(__HP_aCC, < 60700)
415 typedef is_convertible_impl_select<
416 ::boost::is_arithmetic<From>::value,
417 ::boost::is_arithmetic<To>::value,
418 #ifndef BOOST_NO_IS_ABSTRACT
419 ::boost::is_abstract<To>::value
425 typedef is_convertible_impl_select<false, false, false> selector;
427 typedef typename selector::template rebind<From, To> isc_binder;
428 typedef typename isc_binder::type type;
431 template <typename From, typename To>
432 struct is_convertible_impl_dispatch
433 : public is_convertible_impl_dispatch_base<From, To>::type
437 // Now add the full and partial specialisations
438 // for void types, these are common to all the
439 // implementation above:
441 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
442 # define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \
443 BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2,value) \
444 BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const,value) \
445 BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 volatile,value) \
446 BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const volatile,value) \
449 # define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(trait,spec1,spec2,value) \
450 TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \
451 TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const,spec2,value) \
452 TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 volatile,spec2,value) \
453 TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const volatile,spec2,value) \
456 TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(is_convertible,void,void,true)
458 # undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2
459 # undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1
462 BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(is_convertible,void,void,true)
463 #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS
465 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
466 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void,To,false)
467 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void,false)
468 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
469 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const,To,false)
470 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void volatile,To,false)
471 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const volatile,To,false)
472 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const,false)
473 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void volatile,false)
474 BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const volatile,false)
476 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
478 } // namespace detail
480 BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,(::boost::detail::is_convertible_impl_dispatch<From,To>::value))
484 BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,BOOST_IS_CONVERTIBLE(From,To))
490 #include <boost/type_traits/detail/bool_trait_undef.hpp>
492 #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED