]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | #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> | |
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/type_traits/declval.hpp> | |
35 | #endif | |
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 | |
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) && !(defined(BOOST_GCC) && (BOOST_GCC < 40700)) | |
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 | ||
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> | |
309 | {}; | |
310 | ||
311 | template <typename From> | |
312 | struct is_convertible_basic_impl_add_lvalue_reference<From[]> | |
313 | { | |
314 | typedef From type []; | |
315 | }; | |
316 | ||
317 | template <typename From, typename To> | |
318 | struct is_convertible_basic_impl | |
319 | { | |
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; | |
324 | #ifdef BOOST_MSVC | |
325 | #pragma warning(push) | |
326 | #pragma warning(disable:4244) | |
327 | #if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000) | |
328 | #pragma warning(disable:6334) | |
329 | #endif | |
330 | #endif | |
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) | |
335 | ); | |
336 | #else | |
337 | BOOST_STATIC_CONSTANT(bool, value = | |
338 | sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type) | |
339 | ); | |
340 | #endif | |
341 | #ifdef BOOST_MSVC | |
342 | #pragma warning(pop) | |
343 | #endif | |
344 | }; | |
345 | ||
346 | #endif // is_convertible_impl | |
347 | ||
348 | #if defined(__DMC__) | |
349 | // As before, a static constant sometimes causes errors on Digital Mars. | |
350 | template <typename From, typename To> | |
351 | struct is_convertible_impl | |
352 | { | |
353 | enum { | |
354 | value = ( ::boost::detail::is_convertible_basic_impl<From,To>::value && ! ::boost::is_array<To>::value && ! ::boost::is_function<To>::value) | |
355 | }; | |
356 | }; | |
357 | #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551 | |
358 | template <typename From, typename To> | |
359 | struct is_convertible_impl | |
360 | { | |
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)); | |
362 | }; | |
363 | #endif | |
364 | ||
365 | template <bool trivial1, bool trivial2, bool abstract_target> | |
366 | struct is_convertible_impl_select | |
367 | { | |
368 | template <class From, class To> | |
369 | struct rebind | |
370 | { | |
371 | typedef is_convertible_impl<From, To> type; | |
372 | }; | |
373 | }; | |
374 | ||
375 | template <> | |
376 | struct is_convertible_impl_select<true, true, false> | |
377 | { | |
378 | template <class From, class To> | |
379 | struct rebind | |
380 | { | |
381 | typedef true_type type; | |
382 | }; | |
383 | }; | |
384 | ||
385 | template <> | |
386 | struct is_convertible_impl_select<false, false, true> | |
387 | { | |
388 | template <class From, class To> | |
389 | struct rebind | |
390 | { | |
391 | typedef false_type type; | |
392 | }; | |
393 | }; | |
394 | ||
395 | template <> | |
396 | struct is_convertible_impl_select<true, false, true> | |
397 | { | |
398 | template <class From, class To> | |
399 | struct rebind | |
400 | { | |
401 | typedef false_type type; | |
402 | }; | |
403 | }; | |
404 | ||
405 | template <typename From, typename To> | |
406 | struct is_convertible_impl_dispatch_base | |
407 | { | |
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 | |
415 | #else | |
416 | false | |
417 | #endif | |
418 | > selector; | |
419 | #else | |
420 | typedef is_convertible_impl_select<false, false, false> selector; | |
421 | #endif | |
422 | typedef typename selector::template rebind<From, To> isc_binder; | |
423 | typedef typename isc_binder::type type; | |
424 | }; | |
425 | ||
426 | template <typename From, typename To> | |
427 | struct is_convertible_impl_dispatch | |
428 | : public is_convertible_impl_dispatch_base<From, To>::type | |
429 | {}; | |
430 | ||
431 | // | |
432 | // Now add the full and partial specialisations | |
433 | // for void types, these are common to all the | |
434 | // implementation above: | |
435 | // | |
436 | #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS | |
437 | ||
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{}; | |
442 | ||
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{}; | |
447 | ||
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{}; | |
452 | ||
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{}; | |
457 | ||
458 | #else | |
459 | template <> struct is_convertible_impl_dispatch<void, void> : public true_type{}; | |
460 | #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS | |
461 | ||
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{}; | |
464 | ||
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{}; | |
472 | #endif | |
473 | ||
474 | } // namespace detail | |
475 | ||
476 | template <class From, class To> | |
477 | struct is_convertible : public integral_constant<bool, ::boost::detail::is_convertible_impl_dispatch<From, To>::value> {}; | |
478 | ||
479 | #else | |
480 | ||
481 | template <class From, class To> | |
482 | struct is_convertible : public integral_constant<bool, BOOST_IS_CONVERTIBLE(From, To)> {}; | |
483 | ||
484 | #endif | |
485 | ||
486 | } // namespace boost | |
487 | ||
488 | #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED |