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
15The lack of preservation of range makes conversions between numeric types
16error prone. This is true for both implicit conversions and explicit
17conversions (through `static_cast`).
18[link boost_numericconversion.improved_numeric_cast__.numeric_cast `numeric_cast`]
19detects loss of range when a numeric type is converted, and throws an
20exception if the range cannot be preserved.
21
22There 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
28The C++ Standard does not specify the behavior when a numeric type is
29assigned a value that cannot be represented by the type, except for unsigned
30integral 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
32greater than the largest value that can be represented). The fact that the
33behavior for overflow is undefined for all conversions (except the
34aforementioned unsigned to unsigned) makes any code that may produce
35positive or negative overflows exposed to portability issues.
36
37By default `numeric_cast` adheres to the rules for implicit conversions mandated by
38the C++ Standard, such as truncating floating point types when converting
39to integral types. The implementation must guarantee that for a conversion
40to a type that can hold all possible values of the source type, there will
41be 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
66to a value of type Target. If out-of-range is detected, an overflow policy
67is 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
85The behavior of `numeric_cast` may be tailored for custom numeric types through
86the specialization of `numeric_cast_traits`. (see
87[link boost_numericconversion.type_requirements_and_user_defined_types_support User Defined Types]
88for details.
89)
90
91[endsect]
92
93[section Examples]
94
95The 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]
154