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