1
2// Copyright 2000 John Maddock ([email protected])
3// Copyright 2000 Jeremy Siek ([email protected])
4// Copyright 1999, 2000 Jaakko Jarvi ([email protected])
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
41namespace 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
55namespace 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//
101template <typename From, typename To>
102struct 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
123struct 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
131template <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
137template <typename From, typename To>
138struct 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//
166struct 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
176template <typename From, typename To>
177struct 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
198struct 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
208template <typename From, typename To>
209struct 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
240template <typename From, typename To,bool FromIsFunctionRef>
241struct is_convertible_basic_impl_aux;
242
243struct 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
251template <typename From, typename To>
252struct 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
271template <typename From, typename To>
272struct 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
290template <typename From, typename To>
291struct 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//
303template <typename From, typename To>
304struct 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.
336template <typename From, typename To>
337struct 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
354template <typename From, typename To>
355struct 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
374template <bool trivial1, bool trivial2, bool abstract_target>
375struct 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
384template <>
385struct 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
394template <>
395struct 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
404template <>
405struct 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
414template <typename From, typename To>
415struct 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
435template <typename From, typename To>
436struct 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
469BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void,To,false)
470BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void,false)
471#ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
472BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const,To,false)
473BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void volatile,To,false)
474BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const volatile,To,false)
475BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const,false)
476BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void volatile,false)
477BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const volatile,false)
478#endif
479
480} // namespace detail
481
482BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,(::boost::detail::is_convertible_impl_dispatch<From,To>::value))
483
484#else
485
486BOOST_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