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 | |
45 | namespace 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 | |
59 | namespace 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(BOOST_BORLANDC) && (BOOST_BORLANDC < 0x560) |
100 | // |
101 | // special version for Borland compilers |
102 | // this version breaks when used for some |
103 | // UDT conversions: |
104 | // |
105 | template <typename From, typename To> |
106 | struct 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(BOOST_BORLANDC) && (BOOST_BORLANDC < 0x600) |
124 | // special version for gcc compiler + recent Borland versions |
125 | // note that this does not pass UDT's through (...) |
126 | |
127 | struct 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 | |
135 | template <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 | |
141 | template <typename From, typename To> |
142 | struct 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 | // |
170 | struct 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 | |
180 | template <typename From, typename To> |
181 | struct 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 | |
202 | struct 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 | |
212 | template <typename From, typename To> |
213 | struct 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 | |
244 | template <typename From, typename To,bool FromIsFunctionRef> |
245 | struct is_convertible_basic_impl_aux; |
246 | |
247 | struct 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 | |
255 | template <typename From, typename To> |
256 | struct 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 | |
275 | template <typename From, typename To> |
276 | struct 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 | |
294 | template <typename From, typename To> |
295 | struct 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 |
310 | template <typename From> |
311 | struct is_convertible_basic_impl_add_lvalue_reference |
312 | : add_lvalue_reference<From> |
313 | {}; |
314 | |
315 | template <typename From> |
316 | struct is_convertible_basic_impl_add_lvalue_reference<From[]> |
317 | { |
318 | typedef From type []; |
319 | }; |
320 | |
321 | template <typename From, typename To> |
322 | struct 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. |
354 | template <typename From, typename To> |
355 | struct 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(BOOST_BORLANDC) || BOOST_BORLANDC > 0x551 |
362 | template <typename From, typename To> |
363 | struct 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 | |
369 | template <bool trivial1, bool trivial2, bool abstract_target> |
370 | struct 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 | |
379 | template <> |
380 | struct 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 | |
389 | template <> |
390 | struct 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 | |
399 | template <> |
400 | struct 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 | |
409 | template <typename From, typename To> |
410 | struct 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 | |
430 | template <typename From, typename To> |
431 | struct 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 | |
442 | template <> struct is_convertible_impl_dispatch<void, void> : public true_type{}; |
443 | template <> struct is_convertible_impl_dispatch<void, void const> : public true_type{}; |
444 | template <> struct is_convertible_impl_dispatch<void, void const volatile> : public true_type{}; |
445 | template <> struct is_convertible_impl_dispatch<void, void volatile> : public true_type{}; |
446 | |
447 | template <> struct is_convertible_impl_dispatch<void const, void> : public true_type{}; |
448 | template <> struct is_convertible_impl_dispatch<void const, void const> : public true_type{}; |
449 | template <> struct is_convertible_impl_dispatch<void const, void const volatile> : public true_type{}; |
450 | template <> struct is_convertible_impl_dispatch<void const, void volatile> : public true_type{}; |
451 | |
452 | template <> struct is_convertible_impl_dispatch<void const volatile, void> : public true_type{}; |
453 | template <> struct is_convertible_impl_dispatch<void const volatile, void const> : public true_type{}; |
454 | template <> struct is_convertible_impl_dispatch<void const volatile, void const volatile> : public true_type{}; |
455 | template <> struct is_convertible_impl_dispatch<void const volatile, void volatile> : public true_type{}; |
456 | |
457 | template <> struct is_convertible_impl_dispatch<void volatile, void> : public true_type{}; |
458 | template <> struct is_convertible_impl_dispatch<void volatile, void const> : public true_type{}; |
459 | template <> struct is_convertible_impl_dispatch<void volatile, void const volatile> : public true_type{}; |
460 | template <> struct is_convertible_impl_dispatch<void volatile, void volatile> : public true_type{}; |
461 | |
462 | #else |
463 | template <> struct is_convertible_impl_dispatch<void, void> : public true_type{}; |
464 | #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS |
465 | |
466 | template <class To> struct is_convertible_impl_dispatch<void, To> : public false_type{}; |
467 | template <class From> struct is_convertible_impl_dispatch<From, void> : public false_type{}; |
468 | |
469 | #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS |
470 | template <class To> struct is_convertible_impl_dispatch<void const, To> : public false_type{}; |
471 | template <class From> struct is_convertible_impl_dispatch<From, void const> : public false_type{}; |
472 | template <class To> struct is_convertible_impl_dispatch<void const volatile, To> : public false_type{}; |
473 | template <class From> struct is_convertible_impl_dispatch<From, void const volatile> : public false_type{}; |
474 | template <class To> struct is_convertible_impl_dispatch<void volatile, To> : public false_type{}; |
475 | template <class From> struct is_convertible_impl_dispatch<From, void volatile> : public false_type{}; |
476 | #endif |
477 | |
478 | } // namespace detail |
479 | |
480 | template <class From, class To> |
481 | struct 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 | |
489 | template <class From, class To> |
490 | struct 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 | |