Home | Libraries | People | FAQ | More |
The lack of preservation of range makes conversions between numeric types
error prone. This is true for both implicit conversions and explicit conversions
(through static_cast
). numeric_cast
detects loss of range
when a numeric type is converted, and throws an exception if the range cannot
be preserved.
There are several situations where conversions are unsafe:
The C++ Standard does not specify the behavior when a numeric type is assigned a value that cannot be represented by the type, except for unsigned integral types [3.9.1.4], which must obey the laws of arithmetic modulo 2n (this implies that the result will be reduced modulo the number that is one greater than the largest value that can be represented). The fact that the behavior for overflow is undefined for all conversions (except the aforementioned unsigned to unsigned) makes any code that may produce positive or negative overflows exposed to portability issues.
By default numeric_cast
adheres
to the rules for implicit conversions mandated by the C++ Standard, such
as truncating floating point types when converting to integral types. The
implementation must guarantee that for a conversion to a type that can hold
all possible values of the source type, there will be no runtime overhead.
template <typename Target, typename Source> inline Target numeric_cast( Source arg ) { typedef conversion_traits<Target, Source> conv_traits; typedef numeric_cast_traits<Target, Source> cast_traits; typedef converter < Target, Source, conv_traits, typename cast_traits::overflow_policy, typename cast_traits::rounding_policy, raw_converter<conv_traits>, typename cast_traits::range_checking_policy > converter; return converter::convert(arg); }
numeric_cast
returns the
result of converting a value of type Source to a value of type Target. If
out-of-range is detected, an overflow policy is executed whose default behavior
is to throw an an exception (see bad_numeric_cast,
negative_overflow
and positive_overflow
).
template <typename Target, typename Source, typename EnableIf = void> struct numeric_cast_traits { typedef def_overflow_handler overflow_policy; typedef UseInternalRangeChecker range_checking_policy; typedef Trunc<Source> rounding_policy; };
The behavior of numeric_cast
may be tailored for custom numeric types through the specialization of numeric_cast_traits
. (see User
Defined Types for details. )
The following example performs some typical conversions between numeric types:
int main() { using boost::numeric_cast; using boost::numeric::bad_numeric_cast; using boost::numeric::positive_overflow; using boost::numeric::negative_overflow; try { int i=42; short s=numeric_cast<short>(i); // This conversion succeeds (is in range) } catch(negative_overflow& e) { std::cout << e.what(); } catch(positive_overflow& e) { std::cout << e.what(); } try { float f=-42.1234; // This will cause a boost::numeric::negative_overflow exception to be thrown unsigned int i=numeric_cast<unsigned int>(f); } catch(bad_numeric_cast& e) { std::cout << e.what(); } double d= f + numeric_cast<double>(123); // int -> double unsigned long l=std::numeric_limits<unsigned long>::max(); try { // This will cause a boost::numeric::positive_overflow exception to be thrown // NOTE: *operations* on unsigned integral types cannot cause overflow // but *conversions* to a signed type ARE range checked by numeric_cast. unsigned char c=numeric_cast<unsigned char>(l); } catch(positive_overflow& e) { std::cout << e.what(); } return 0; }