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