is_convertible.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // Copyright 2000 John Maddock (john@johnmaddock.co.uk)
  2. // Copyright 2000 Jeremy Siek (jsiek@lsc.nd.edu)
  3. // Copyright 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
  4. //
  5. // Use, modification and distribution are subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt).
  8. //
  9. // See http://www.boost.org/libs/type_traits for most recent version including documentation.
  10. #ifndef BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
  11. #define BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED
  12. #include <boost/type_traits/intrinsics.hpp>
  13. #include <boost/type_traits/integral_constant.hpp>
  14. #include <boost/type_traits/is_complete.hpp>
  15. #include <boost/type_traits/is_void.hpp>
  16. #include <boost/type_traits/is_array.hpp>
  17. #include <boost/static_assert.hpp>
  18. #ifndef BOOST_IS_CONVERTIBLE
  19. #include <boost/type_traits/detail/yes_no_type.hpp>
  20. #include <boost/type_traits/detail/config.hpp>
  21. #include <boost/type_traits/is_array.hpp>
  22. #include <boost/type_traits/is_arithmetic.hpp>
  23. #include <boost/type_traits/is_void.hpp>
  24. #if !defined(BOOST_NO_IS_ABSTRACT)
  25. #include <boost/type_traits/is_abstract.hpp>
  26. #endif
  27. #include <boost/type_traits/add_lvalue_reference.hpp>
  28. #include <boost/type_traits/add_rvalue_reference.hpp>
  29. #include <boost/type_traits/is_function.hpp>
  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. namespace boost {
  41. #ifndef BOOST_IS_CONVERTIBLE
  42. // is one type convertible to another?
  43. //
  44. // there are multiple versions of the is_convertible
  45. // template, almost every compiler seems to require its
  46. // own version.
  47. //
  48. // Thanks to Andrei Alexandrescu for the original version of the
  49. // conversion detection technique!
  50. //
  51. namespace detail {
  52. #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !(defined(BOOST_GCC) && (BOOST_GCC < 40700))
  53. // This is a C++11 conforming version, place this first and use it wherever possible:
  54. # define BOOST_TT_CXX11_IS_CONVERTIBLE
  55. template <class A, class B, class C>
  56. struct or_helper
  57. {
  58. static const bool value = (A::value || B::value || C::value);
  59. };
  60. template<typename From, typename To, bool b = or_helper<boost::is_void<From>, boost::is_function<To>, boost::is_array<To> >::value>
  61. struct is_convertible_basic_impl
  62. {
  63. // Nothing converts to function or array, but void converts to void:
  64. static const bool value = is_void<To>::value;
  65. };
  66. template<typename From, typename To>
  67. class is_convertible_basic_impl<From, To, false>
  68. {
  69. typedef char one;
  70. typedef int two;
  71. template<typename To1>
  72. static void test_aux(To1);
  73. template<typename From1, typename To1>
  74. static decltype(test_aux<To1>(boost::declval<From1>()), one()) test(int);
  75. template<typename, typename>
  76. static two test(...);
  77. public:
  78. static const bool value = sizeof(test<From, To>(0)) == 1;
  79. };
  80. #elif defined(__BORLANDC__) && (__BORLANDC__ < 0x560)
  81. //
  82. // special version for Borland compilers
  83. // this version breaks when used for some
  84. // UDT conversions:
  85. //
  86. template <typename From, typename To>
  87. struct is_convertible_impl
  88. {
  89. #pragma option push -w-8074
  90. // This workaround for Borland breaks the EDG C++ frontend,
  91. // so we only use it for Borland.
  92. template <typename T> struct checker
  93. {
  94. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
  95. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(T);
  96. };
  97. static typename add_lvalue_reference<From>::type _m_from;
  98. static bool const value = sizeof( checker<To>::_m_check(_m_from) )
  99. == sizeof(::boost::type_traits::yes_type);
  100. #pragma option pop
  101. };
  102. #elif defined(__GNUC__) || defined(__BORLANDC__) && (__BORLANDC__ < 0x600)
  103. // special version for gcc compiler + recent Borland versions
  104. // note that this does not pass UDT's through (...)
  105. struct any_conversion
  106. {
  107. template <typename T> any_conversion(const volatile T&);
  108. template <typename T> any_conversion(const T&);
  109. template <typename T> any_conversion(volatile T&);
  110. template <typename T> any_conversion(T&);
  111. };
  112. template <typename T> struct checker
  113. {
  114. static boost::type_traits::no_type _m_check(any_conversion ...);
  115. static boost::type_traits::yes_type _m_check(T, int);
  116. };
  117. template <typename From, typename To>
  118. struct is_convertible_basic_impl
  119. {
  120. typedef typename add_lvalue_reference<From>::type lvalue_type;
  121. typedef typename add_rvalue_reference<From>::type rvalue_type;
  122. static lvalue_type _m_from;
  123. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)))
  124. static bool const value =
  125. sizeof( boost::detail::checker<To>::_m_check(static_cast<rvalue_type>(_m_from), 0) )
  126. == sizeof(::boost::type_traits::yes_type);
  127. #else
  128. static bool const value =
  129. sizeof( boost::detail::checker<To>::_m_check(_m_from, 0) )
  130. == sizeof(::boost::type_traits::yes_type);
  131. #endif
  132. };
  133. #elif (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 245) && !defined(__ICL)) \
  134. || defined(__IBMCPP__) || defined(__HP_aCC)
  135. //
  136. // This is *almost* an ideal world implementation as it doesn't rely
  137. // on undefined behaviour by passing UDT's through (...).
  138. // Unfortunately it doesn't quite pass all the tests for most compilers (sigh...)
  139. // Enable this for your compiler if is_convertible_test.cpp will compile it...
  140. //
  141. // Note we do not enable this for VC7.1, because even though it passes all the
  142. // type_traits tests it is known to cause problems when instantiation occurs
  143. // deep within the instantiation tree :-(
  144. //
  145. struct any_conversion
  146. {
  147. template <typename T> any_conversion(const volatile T&);
  148. template <typename T> any_conversion(const T&);
  149. template <typename T> any_conversion(volatile T&);
  150. // we need this constructor to catch references to functions
  151. // (which can not be cv-qualified):
  152. template <typename T> any_conversion(T&);
  153. };
  154. template <typename From, typename To>
  155. struct is_convertible_basic_impl
  156. {
  157. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
  158. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
  159. typedef typename add_lvalue_reference<From>::type lvalue_type;
  160. typedef typename add_rvalue_reference<From>::type rvalue_type;
  161. static lvalue_type _m_from;
  162. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  163. BOOST_STATIC_CONSTANT(bool, value =
  164. sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
  165. );
  166. #else
  167. BOOST_STATIC_CONSTANT(bool, value =
  168. sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
  169. );
  170. #endif
  171. };
  172. #elif defined(__DMC__)
  173. struct any_conversion
  174. {
  175. template <typename T> any_conversion(const volatile T&);
  176. template <typename T> any_conversion(const T&);
  177. template <typename T> any_conversion(volatile T&);
  178. // we need this constructor to catch references to functions
  179. // (which can not be cv-qualified):
  180. template <typename T> any_conversion(T&);
  181. };
  182. template <typename From, typename To>
  183. struct is_convertible_basic_impl
  184. {
  185. // Using '...' doesn't always work on Digital Mars. This version seems to.
  186. template <class T>
  187. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion, float, T);
  188. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int, int);
  189. typedef typename add_lvalue_reference<From>::type lvalue_type;
  190. typedef typename add_rvalue_reference<From>::type rvalue_type;
  191. static lvalue_type _m_from;
  192. // Static constants sometime cause the conversion of _m_from to To to be
  193. // called. This doesn't happen with an enum.
  194. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  195. enum { value =
  196. sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0, 0) ) == sizeof(::boost::type_traits::yes_type)
  197. };
  198. #else
  199. enum { value =
  200. sizeof( _m_check(_m_from, 0, 0) ) == sizeof(::boost::type_traits::yes_type)
  201. };
  202. #endif
  203. };
  204. #elif defined(__MWERKS__)
  205. //
  206. // CW works with the technique implemented above for EDG, except when From
  207. // is a function type (or a reference to such a type), in which case
  208. // any_conversion won't be accepted as a valid conversion. We detect this
  209. // exceptional situation and channel it through an alternative algorithm.
  210. //
  211. template <typename From, typename To,bool FromIsFunctionRef>
  212. struct is_convertible_basic_impl_aux;
  213. struct any_conversion
  214. {
  215. template <typename T> any_conversion(const volatile T&);
  216. template <typename T> any_conversion(const T&);
  217. template <typename T> any_conversion(volatile T&);
  218. template <typename T> any_conversion(T&);
  219. };
  220. template <typename From, typename To>
  221. struct is_convertible_basic_impl_aux<From,To,false /*FromIsFunctionRef*/>
  222. {
  223. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...);
  224. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int);
  225. typedef typename add_lvalue_reference<From>::type lvalue_type;
  226. typedef typename add_rvalue_reference<From>::type rvalue_type;
  227. static lvalue_type _m_from;
  228. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  229. BOOST_STATIC_CONSTANT(bool, value =
  230. sizeof( _m_check(static_cast<rvalue_type>(_m_from), 0) ) == sizeof(::boost::type_traits::yes_type)
  231. );
  232. #else
  233. BOOST_STATIC_CONSTANT(bool, value =
  234. sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type)
  235. );
  236. #endif
  237. };
  238. template <typename From, typename To>
  239. struct is_convertible_basic_impl_aux<From,To,true /*FromIsFunctionRef*/>
  240. {
  241. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
  242. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
  243. typedef typename add_lvalue_reference<From>::type lvalue_type;
  244. typedef typename add_rvalue_reference<From>::type rvalue_type;
  245. static lvalue_type _m_from;
  246. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  247. BOOST_STATIC_CONSTANT(bool, value =
  248. sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
  249. );
  250. #else
  251. BOOST_STATIC_CONSTANT(bool, value =
  252. sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
  253. );
  254. #endif
  255. };
  256. template <typename From, typename To>
  257. struct is_convertible_basic_impl:
  258. is_convertible_basic_impl_aux<
  259. From,To,
  260. ::boost::is_function<typename ::boost::remove_reference<From>::type>::value
  261. >
  262. {};
  263. #else
  264. //
  265. // This version seems to work pretty well for a wide spectrum of compilers,
  266. // however it does rely on undefined behaviour by passing UDT's through (...).
  267. //
  268. //Workaround for old compilers like MSVC 7.1 to avoid
  269. //forming a reference to an array of unknown bound
  270. template <typename From>
  271. struct is_convertible_basic_impl_add_lvalue_reference
  272. : add_lvalue_reference<From>
  273. {};
  274. template <typename From>
  275. struct is_convertible_basic_impl_add_lvalue_reference<From[]>
  276. {
  277. typedef From type [];
  278. };
  279. template <typename From, typename To>
  280. struct is_convertible_basic_impl
  281. {
  282. static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...);
  283. static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To);
  284. typedef typename is_convertible_basic_impl_add_lvalue_reference<From>::type lvalue_type;
  285. static lvalue_type _m_from;
  286. #ifdef BOOST_MSVC
  287. #pragma warning(push)
  288. #pragma warning(disable:4244)
  289. #if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000)
  290. #pragma warning(disable:6334)
  291. #endif
  292. #endif
  293. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  294. typedef typename add_rvalue_reference<From>::type rvalue_type;
  295. BOOST_STATIC_CONSTANT(bool, value =
  296. sizeof( _m_check(static_cast<rvalue_type>(_m_from)) ) == sizeof(::boost::type_traits::yes_type)
  297. );
  298. #else
  299. BOOST_STATIC_CONSTANT(bool, value =
  300. sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type)
  301. );
  302. #endif
  303. #ifdef BOOST_MSVC
  304. #pragma warning(pop)
  305. #endif
  306. };
  307. #endif // is_convertible_impl
  308. #if defined(__DMC__)
  309. // As before, a static constant sometimes causes errors on Digital Mars.
  310. template <typename From, typename To>
  311. struct is_convertible_impl
  312. {
  313. enum {
  314. value = ( ::boost::detail::is_convertible_basic_impl<From,To>::value && ! ::boost::is_array<To>::value && ! ::boost::is_function<To>::value)
  315. };
  316. };
  317. #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551
  318. template <typename From, typename To>
  319. struct is_convertible_impl
  320. {
  321. BOOST_STATIC_CONSTANT(bool, value = ( ::boost::detail::is_convertible_basic_impl<From, To>::value && !::boost::is_array<To>::value && !::boost::is_function<To>::value));
  322. };
  323. #endif
  324. template <bool trivial1, bool trivial2, bool abstract_target>
  325. struct is_convertible_impl_select
  326. {
  327. template <class From, class To>
  328. struct rebind
  329. {
  330. typedef is_convertible_impl<From, To> type;
  331. };
  332. };
  333. template <>
  334. struct is_convertible_impl_select<true, true, false>
  335. {
  336. template <class From, class To>
  337. struct rebind
  338. {
  339. typedef true_type type;
  340. };
  341. };
  342. template <>
  343. struct is_convertible_impl_select<false, false, true>
  344. {
  345. template <class From, class To>
  346. struct rebind
  347. {
  348. typedef false_type type;
  349. };
  350. };
  351. template <>
  352. struct is_convertible_impl_select<true, false, true>
  353. {
  354. template <class From, class To>
  355. struct rebind
  356. {
  357. typedef false_type type;
  358. };
  359. };
  360. template <typename From, typename To>
  361. struct is_convertible_impl_dispatch_base
  362. {
  363. #if !BOOST_WORKAROUND(__HP_aCC, < 60700)
  364. typedef is_convertible_impl_select<
  365. ::boost::is_arithmetic<From>::value,
  366. ::boost::is_arithmetic<To>::value,
  367. #if !defined(BOOST_NO_IS_ABSTRACT) && !defined(BOOST_TT_CXX11_IS_CONVERTIBLE)
  368. // We need to filter out abstract types, only if we don't have a strictly conforming C++11 version:
  369. ::boost::is_abstract<To>::value
  370. #else
  371. false
  372. #endif
  373. > selector;
  374. #else
  375. typedef is_convertible_impl_select<false, false, false> selector;
  376. #endif
  377. typedef typename selector::template rebind<From, To> isc_binder;
  378. typedef typename isc_binder::type type;
  379. };
  380. template <typename From, typename To>
  381. struct is_convertible_impl_dispatch
  382. : public is_convertible_impl_dispatch_base<From, To>::type
  383. {};
  384. //
  385. // Now add the full and partial specialisations
  386. // for void types, these are common to all the
  387. // implementation above:
  388. //
  389. #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
  390. template <> struct is_convertible_impl_dispatch<void, void> : public true_type{};
  391. template <> struct is_convertible_impl_dispatch<void, void const> : public true_type{};
  392. template <> struct is_convertible_impl_dispatch<void, void const volatile> : public true_type{};
  393. template <> struct is_convertible_impl_dispatch<void, void volatile> : public true_type{};
  394. template <> struct is_convertible_impl_dispatch<void const, void> : public true_type{};
  395. template <> struct is_convertible_impl_dispatch<void const, void const> : public true_type{};
  396. template <> struct is_convertible_impl_dispatch<void const, void const volatile> : public true_type{};
  397. template <> struct is_convertible_impl_dispatch<void const, void volatile> : public true_type{};
  398. template <> struct is_convertible_impl_dispatch<void const volatile, void> : public true_type{};
  399. template <> struct is_convertible_impl_dispatch<void const volatile, void const> : public true_type{};
  400. template <> struct is_convertible_impl_dispatch<void const volatile, void const volatile> : public true_type{};
  401. template <> struct is_convertible_impl_dispatch<void const volatile, void volatile> : public true_type{};
  402. template <> struct is_convertible_impl_dispatch<void volatile, void> : public true_type{};
  403. template <> struct is_convertible_impl_dispatch<void volatile, void const> : public true_type{};
  404. template <> struct is_convertible_impl_dispatch<void volatile, void const volatile> : public true_type{};
  405. template <> struct is_convertible_impl_dispatch<void volatile, void volatile> : public true_type{};
  406. #else
  407. template <> struct is_convertible_impl_dispatch<void, void> : public true_type{};
  408. #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS
  409. template <class To> struct is_convertible_impl_dispatch<void, To> : public false_type{};
  410. template <class From> struct is_convertible_impl_dispatch<From, void> : public false_type{};
  411. #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
  412. template <class To> struct is_convertible_impl_dispatch<void const, To> : public false_type{};
  413. template <class From> struct is_convertible_impl_dispatch<From, void const> : public false_type{};
  414. template <class To> struct is_convertible_impl_dispatch<void const volatile, To> : public false_type{};
  415. template <class From> struct is_convertible_impl_dispatch<From, void const volatile> : public false_type{};
  416. template <class To> struct is_convertible_impl_dispatch<void volatile, To> : public false_type{};
  417. template <class From> struct is_convertible_impl_dispatch<From, void volatile> : public false_type{};
  418. #endif
  419. } // namespace detail
  420. template <class From, class To>
  421. struct is_convertible : public integral_constant<bool, ::boost::detail::is_convertible_impl_dispatch<From, To>::value>
  422. {
  423. 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");
  424. 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");
  425. };
  426. #else
  427. template <class From, class To>
  428. struct is_convertible : public integral_constant<bool, BOOST_IS_CONVERTIBLE(From, To)>
  429. {
  430. #if BOOST_WORKAROUND(BOOST_MSVC, <= 1900)
  431. 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");
  432. #endif
  433. #if defined(__clang__)
  434. // clang's intrinsic doesn't assert on incomplete types:
  435. 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");
  436. 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");
  437. #endif
  438. };
  439. #endif
  440. } // namespace boost
  441. #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED