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