numeric_cast.qbk 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. [/
  2. Boost.Optional
  3. Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
  4. Distributed under the Boost Software License, Version 1.0.
  5. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. ]
  8. [section Improved numeric_cast<>]
  9. [section Introduction]
  10. The lack of preservation of range makes conversions between numeric types
  11. error prone. This is true for both implicit conversions and explicit
  12. conversions (through `static_cast`).
  13. [link boost_numericconversion.improved_numeric_cast__.numeric_cast `numeric_cast`]
  14. detects loss of range when a numeric type is converted, and throws an
  15. exception if the range cannot be preserved.
  16. There are several situations where conversions are unsafe:
  17. * Conversions from an integral type with a wider range than the target integral type.
  18. * Conversions from unsigned to signed (and vice versa) integral types.
  19. * Conversions from floating point types to integral types.
  20. The C++ Standard does not specify the behavior when a numeric type is
  21. assigned a value that cannot be represented by the type, except for unsigned
  22. integral types \[3.9.1.4\], which must obey the laws of arithmetic modulo 2n
  23. (this implies that the result will be reduced modulo the number that is one
  24. greater than the largest value that can be represented). The fact that the
  25. behavior for overflow is undefined for all conversions (except the
  26. aforementioned unsigned to unsigned) makes any code that may produce
  27. positive or negative overflows exposed to portability issues.
  28. By default `numeric_cast` adheres to the rules for implicit conversions mandated by
  29. the C++ Standard, such as truncating floating point types when converting
  30. to integral types. The implementation must guarantee that for a conversion
  31. to a type that can hold all possible values of the source type, there will
  32. be no runtime overhead.
  33. [endsect]
  34. [section numeric_cast]
  35. template <typename Target, typename Source> inline
  36. Target numeric_cast( Source arg )
  37. {
  38. typedef conversion_traits<Target, Source> conv_traits;
  39. typedef numeric_cast_traits<Target, Source> cast_traits;
  40. typedef converter
  41. <
  42. Target,
  43. Source,
  44. conv_traits,
  45. typename cast_traits::overflow_policy,
  46. typename cast_traits::rounding_policy,
  47. raw_converter<conv_traits>,
  48. typename cast_traits::range_checking_policy
  49. > converter;
  50. return converter::convert(arg);
  51. }
  52. `numeric_cast` returns the result of converting a value of type Source
  53. to a value of type Target. If out-of-range is detected, an overflow policy
  54. is executed whose default behavior is to throw an an exception (see
  55. [link numeric_conversion_bad_numeric_cast bad_numeric_cast],
  56. [link numeric_conversion_negative_overflow negative_overflow] and
  57. [link numeric_conversion_possitive_overflow positive_overflow]
  58. ).
  59. [endsect]
  60. [section numeric_cast_traits]
  61. template <typename Target, typename Source, typename EnableIf = void>
  62. struct numeric_cast_traits
  63. {
  64. typedef def_overflow_handler overflow_policy;
  65. typedef UseInternalRangeChecker range_checking_policy;
  66. typedef Trunc<Source> rounding_policy;
  67. };
  68. The behavior of `numeric_cast` may be tailored for custom numeric types through
  69. the specialization of `numeric_cast_traits`. (see
  70. [link boost_numericconversion.type_requirements_and_user_defined_types_support User Defined Types]
  71. for details.
  72. )
  73. [endsect]
  74. [section Examples]
  75. The following example performs some typical conversions between numeric types:
  76. #include <boost/numeric/conversion/cast.hpp>
  77. #include <iostream>
  78. int main()
  79. {
  80. using boost::numeric_cast;
  81. using boost::numeric::bad_numeric_cast;
  82. using boost::numeric::positive_overflow;
  83. using boost::numeric::negative_overflow;
  84. try
  85. {
  86. int i=42;
  87. short s=numeric_cast<short>(i); // This conversion succeeds (is in range)
  88. }
  89. catch(negative_overflow& e) {
  90. std::cout << e.what();
  91. }
  92. catch(positive_overflow& e) {
  93. std::cout << e.what();
  94. }
  95. try
  96. {
  97. float f=-42.1234;
  98. // This will cause a boost::numeric::negative_overflow exception to be thrown
  99. unsigned int i=numeric_cast<unsigned int>(f);
  100. }
  101. catch(bad_numeric_cast& e) {
  102. std::cout << e.what();
  103. }
  104. double d= f + numeric_cast<double>(123); // int -> double
  105. unsigned long l=std::numeric_limits<unsigned long>::max();
  106. try
  107. {
  108. // This will cause a boost::numeric::positive_overflow exception to be thrown
  109. // NOTE: *operations* on unsigned integral types cannot cause overflow
  110. // but *conversions* to a signed type ARE range checked by numeric_cast.
  111. unsigned char c=numeric_cast<unsigned char>(l);
  112. }
  113. catch(positive_overflow& e) {
  114. std::cout << e.what();
  115. }
  116. return 0;
  117. }
  118. [endsect]
  119. [endsect]