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 | |
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 | |