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