507d157d10
[SVN r73675]
154 lines
5.0 KiB
Plaintext
154 lines
5.0 KiB
Plaintext
[/
|
|
Boost.Optional
|
|
|
|
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
|
|
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)
|
|
]
|
|
|
|
[section Improved numeric_cast<>]
|
|
|
|
[section Introduction]
|
|
|
|
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`).
|
|
[link boost_numericconversion.improved_numeric_cast__.numeric_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:
|
|
|
|
* Conversions from an integral type with a wider range than the target integral type.
|
|
* Conversions from unsigned to signed (and vice versa) integral types.
|
|
* Conversions from floating point types to integral types.
|
|
|
|
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.
|
|
|
|
[endsect]
|
|
|
|
[section numeric_cast]
|
|
|
|
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
|
|
[link numeric_conversion_bad_numeric_cast bad_numeric_cast],
|
|
[link numeric_conversion_negative_overflow negative_overflow] and
|
|
[link numeric_conversion_possitive_overflow positive_overflow]
|
|
).
|
|
|
|
[endsect]
|
|
|
|
[section numeric_cast_traits]
|
|
|
|
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
|
|
[link boost_numericconversion.type_requirements_and_user_defined_types_support User Defined Types]
|
|
for details.
|
|
)
|
|
|
|
[endsect]
|
|
|
|
[section Examples]
|
|
|
|
The following example performs some typical conversions between numeric types:
|
|
|
|
#include <boost/numeric/conversion/cast.hpp>
|
|
#include <iostream>
|
|
|
|
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;
|
|
}
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|