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 #include <boost/type_traits/integral_constant.hpp>
17 #ifndef BOOST_IS_CONVERTIBLE
18 #include <boost/type_traits/detail/yes_no_type.hpp>
19 #include <boost/type_traits/detail/config.hpp>
20 #include <boost/type_traits/is_array.hpp>
21 #include <boost/type_traits/is_arithmetic.hpp>
22 #include <boost/type_traits/is_void.hpp>
23 #if !defined(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>
33 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
34 # include <boost/type_traits/declval.hpp>
36 #elif defined(BOOST_MSVC) || defined(BOOST_INTEL)
37 #include <boost/type_traits/is_function.hpp>
38 #include <boost/type_traits/is_same.hpp>
39 #endif // BOOST_IS_CONVERTIBLE
43 #ifndef BOOST_IS_CONVERTIBLE
45 // is one type convertible to another?
47 // there are multiple versions of the is_convertible
48 // template, almost every compiler seems to require its
51 // Thanks to Andrei Alexandrescu for the original version of the
52 // conversion detection technique!
57 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !(defined(BOOST_GCC) && (BOOST_GCC < 40700))
59 // This is a C++11 conforming version, place this first and use it wherever possible:
61 # define BOOST_TT_CXX11_IS_CONVERTIBLE
63 template <class A, class B, class C>
66 static const bool value = (A::value || B::value || C::value);
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
72 // Nothing converts to function or array, but void converts to void:
73 static const bool value = is_void<To>::value;
76 template<typename From, typename To>
77 class is_convertible_basic_impl<From, To, false>
82 template<typename To1>
83 static void test_aux(To1);
85 template<typename From1, typename To1>
86 static decltype(test_aux<To1>(boost::declval<From1>()), one()) test(int);
88 template<typename, typename>
92 static const bool value = sizeof(test<From, To>(0)) == 1;
95 #elif defined(__BORLANDC__) && (__BORLANDC__ < 0x560)
97 // special version for Borland compilers
98 // this version breaks when used for some
101 template <typename From, typename To>
102 struct is_convertible_impl
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
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);
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);
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 (...)
123 struct any_conversion
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&);
131 template <typename T> struct checker
133 static boost::type_traits::no_type _m_check(any_conversion ...);
134 static boost::type_traits::yes_type _m_check(T, int);
137 template <typename From, typename To>
138 struct is_convertible_basic_impl
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);
148 static bool const value =
149 sizeof( boost::detail::checker<To>::_m_check(_m_from, 0) )
150 == sizeof(::boost::type_traits::yes_type);
154 #elif (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 245) && !defined(__ICL)) \
155 || defined(__IBMCPP__) || defined(__HP_aCC)
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...
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 :-(
166 struct any_conversion
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&);
176 template <typename From, typename To>
177 struct is_convertible_basic_impl
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;
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)
190 BOOST_STATIC_CONSTANT(bool, value =
191 sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
196 #elif defined(__DMC__)
198 struct any_conversion
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&);
208 template <typename From, typename To>
209 struct is_convertible_basic_impl
211 // Using '...' doesn't always work on Digital Mars. This version seems to.
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;
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
223 sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0, 0) ) == sizeof(::boost::type_traits::yes_type)
227 sizeof( _m_check(_m_from, 0, 0) ) == sizeof(::boost::type_traits::yes_type)
232 #elif defined(__MWERKS__)
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.
240 template <typename From, typename To,bool FromIsFunctionRef>
241 struct is_convertible_basic_impl_aux;
243 struct any_conversion
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&);
251 template <typename From, typename To>
252 struct is_convertible_basic_impl_aux<From,To,false /*FromIsFunctionRef*/>
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;
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)
265 BOOST_STATIC_CONSTANT(bool, value =
266 sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
271 template <typename From, typename To>
272 struct is_convertible_basic_impl_aux<From,To,true /*FromIsFunctionRef*/>
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)
284 BOOST_STATIC_CONSTANT(bool, value =
285 sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
290 template <typename From, typename To>
291 struct is_convertible_basic_impl:
292 is_convertible_basic_impl_aux<
294 ::boost::is_function<typename ::boost::remove_reference<From>::type>::value
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 (...).
304 //Workaround for old compilers like MSVC 7.1 to avoid
305 //forming a reference to an array of unknown bound
306 template <typename From>
307 struct is_convertible_basic_impl_add_lvalue_reference
308 : add_lvalue_reference<From>
311 template <typename From>
312 struct is_convertible_basic_impl_add_lvalue_reference<From[]>
314 typedef From type [];
317 template <typename From, typename To>
318 struct is_convertible_basic_impl
320 static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
321 static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
322 typedef typename is_convertible_basic_impl_add_lvalue_reference<From>::type lvalue_type;
323 static lvalue_type _m_from;
325 #pragma warning(push)
326 #pragma warning(disable:4244)
327 #if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000)
328 #pragma warning(disable:6334)
331 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
332 typedef typename add_rvalue_reference<From>::type rvalue_type;
333 BOOST_STATIC_CONSTANT(bool, value =
334 sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
337 BOOST_STATIC_CONSTANT(bool, value =
338 sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
346 #endif // is_convertible_impl
349 // As before, a static constant sometimes causes errors on Digital Mars.
350 template <typename From, typename To>
351 struct is_convertible_impl
354 value = ( ::boost::detail::is_convertible_basic_impl<From,To>::value && ! ::boost::is_array<To>::value && ! ::boost::is_function<To>::value)
357 #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551
358 template <typename From, typename To>
359 struct is_convertible_impl
361 BOOST_STATIC_CONSTANT(bool, value = ( ::boost::detail::is_convertible_basic_impl<From, To>::value && !::boost::is_array<To>::value && !::boost::is_function<To>::value));
365 template <bool trivial1, bool trivial2, bool abstract_target>
366 struct is_convertible_impl_select
368 template <class From, class To>
371 typedef is_convertible_impl<From, To> type;
376 struct is_convertible_impl_select<true, true, false>
378 template <class From, class To>
381 typedef true_type type;
386 struct is_convertible_impl_select<false, false, true>
388 template <class From, class To>
391 typedef false_type type;
396 struct is_convertible_impl_select<true, false, true>
398 template <class From, class To>
401 typedef false_type type;
405 template <typename From, typename To>
406 struct is_convertible_impl_dispatch_base
408 #if !BOOST_WORKAROUND(__HP_aCC, < 60700)
409 typedef is_convertible_impl_select<
410 ::boost::is_arithmetic<From>::value,
411 ::boost::is_arithmetic<To>::value,
412 #if !defined(BOOST_NO_IS_ABSTRACT) && !defined(BOOST_TT_CXX11_IS_CONVERTIBLE)
413 // We need to filter out abstract types, only if we don't have a strictly conforming C++11 version:
414 ::boost::is_abstract<To>::value
420 typedef is_convertible_impl_select<false, false, false> selector;
422 typedef typename selector::template rebind<From, To> isc_binder;
423 typedef typename isc_binder::type type;
426 template <typename From, typename To>
427 struct is_convertible_impl_dispatch
428 : public is_convertible_impl_dispatch_base<From, To>::type
432 // Now add the full and partial specialisations
433 // for void types, these are common to all the
434 // implementation above:
436 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
438 template <> struct is_convertible_impl_dispatch<void, void> : public true_type{};
439 template <> struct is_convertible_impl_dispatch<void, void const> : public true_type{};
440 template <> struct is_convertible_impl_dispatch<void, void const volatile> : public true_type{};
441 template <> struct is_convertible_impl_dispatch<void, void volatile> : public true_type{};
443 template <> struct is_convertible_impl_dispatch<void const, void> : public true_type{};
444 template <> struct is_convertible_impl_dispatch<void const, void const> : public true_type{};
445 template <> struct is_convertible_impl_dispatch<void const, void const volatile> : public true_type{};
446 template <> struct is_convertible_impl_dispatch<void const, void volatile> : public true_type{};
448 template <> struct is_convertible_impl_dispatch<void const volatile, void> : public true_type{};
449 template <> struct is_convertible_impl_dispatch<void const volatile, void const> : public true_type{};
450 template <> struct is_convertible_impl_dispatch<void const volatile, void const volatile> : public true_type{};
451 template <> struct is_convertible_impl_dispatch<void const volatile, void volatile> : public true_type{};
453 template <> struct is_convertible_impl_dispatch<void volatile, void> : public true_type{};
454 template <> struct is_convertible_impl_dispatch<void volatile, void const> : public true_type{};
455 template <> struct is_convertible_impl_dispatch<void volatile, void const volatile> : public true_type{};
456 template <> struct is_convertible_impl_dispatch<void volatile, void volatile> : public true_type{};
459 template <> struct is_convertible_impl_dispatch<void, void> : public true_type{};
460 #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS
462 template <class To> struct is_convertible_impl_dispatch<void, To> : public false_type{};
463 template <class From> struct is_convertible_impl_dispatch<From, void> : public false_type{};
465 #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
466 template <class To> struct is_convertible_impl_dispatch<void const, To> : public false_type{};
467 template <class From> struct is_convertible_impl_dispatch<From, void const> : public false_type{};
468 template <class To> struct is_convertible_impl_dispatch<void const volatile, To> : public false_type{};
469 template <class From> struct is_convertible_impl_dispatch<From, void const volatile> : public false_type{};
470 template <class To> struct is_convertible_impl_dispatch<void volatile, To> : public false_type{};
471 template <class From> struct is_convertible_impl_dispatch<From, void volatile> : public false_type{};
474 } // namespace detail
476 template <class From, class To>
477 struct is_convertible : public integral_constant<bool, ::boost::detail::is_convertible_impl_dispatch<From, To>::value> {};
481 template <class From, class To>
482 struct is_convertible : public integral_constant<bool, BOOST_IS_CONVERTIBLE(From, To)> {};
488 #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED