4 Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
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)
11 [section Type Requirements and User-defined-types support]
13 [section Type Requirements]
15 Both arithmetic (built-in) and user-defined numeric types require proper
16 specialization of `std::numeric_limits<>` (that is, with (in-class) integral
19 The library uses `std::numeric_limits<T>::is_specialized` to detect whether
20 the type is builtin or user defined, and `std::numeric_limits<T>::is_integer`,
21 `std::numeric_limits<T>::is_signed` to detect whether the type is integer
22 or floating point; and whether it is signed/unsigned.
24 The default `Float2IntRounder` policies uses unqualified calls to functions
25 `floor()` and `ceil()`; but the standard functions are introduced in scope
28 using std::floor ; return floor(s);
30 Therefore, for builtin arithmetic types, the std functions will be used.
31 User defined types should provide overloaded versions of these functions in
32 order to use the default rounder policies. If these overloads are defined
33 within a user namespace argument dependent lookup (ADL) should find them,
34 but if your compiler has a weak ADL you might need to put these functions
35 some place else or write your own rounder policy.
37 The default `Trunc<>` rounder policy needs to determine if the source value
38 is positive or not, and for this it evaluates the expression
39 `s < static_cast<S>(0)`. Therefore, user defined types require a visible
40 `operator<` in order to use the `Trunc<>` policy (the default).
45 [section UDT's special semantics]
47 [heading Conversion Traits]
49 If a User Defined Type is involved in a conversion, it is ['assumed] that
50 the UDT has [link boost_numericconversion.definitions.range_and_precision wider range]
51 than any built-in type, and consequently the values
52 of some `converter_traits<>` members are hardwired regardless of the reality.
53 The following table summarizes this:
55 * `Target=`['UDT] and `Source=`['built-in]
59 * `Target=`['built-in] and `Source=`['UDT]
64 * `Target=`['UDT] and `Source=`['UDT]
70 The `Traits` member `udt_mixture` can be used to detect whether a UDT is involved
71 and to infer the validity of the other members as shown above.
73 [heading Range Checking]
75 Because User Defined Numeric Types might have peculiar ranges (such as an
76 unbounded range), this library does not attempt to supply a meaningful range
77 checking logic when UDTs are involved in a conversion. Therefore, if either
78 Target or Source are not built-in types, the bundled range checking of the
79 `converter<>` function object is automatically disabled. However, it is possible
80 to supply a user-defined range-checker. See
81 [link boost_numericconversion.type_requirements_and_user_defined_types_support.special_policies Special Policies]
85 [section Special Policies]
87 There are two components of the `converter<>` class that might require special
88 behavior if User Defined Numeric Types are involved: the Range Checking and the
91 When both Target and Source are built-in types, the converter class uses an internal
92 range checking logic which is optimized and customized for the combined properties
95 However, this internal logic is disabled when either type is User Defined.
96 In this case, the user can specify an ['external] range checking policy which will be
97 used in place of the internal code. See
98 [link boost_numericconversion.type_requirements_and_user_defined_types_support.udts_with_numeric_cast numeric_cast_traits]
99 for details on using UDTs with `numeric_cast`.
101 The converter class performs the actual conversion using a Raw Converter policy.
102 The default raw converter simply performs a `static_cast<Target>(source)`.
104 However, if the a UDT is involved, the `static_cast` might not work. In this case,
105 the user can implement and pass a different raw converter policy.
106 See [link boost_numericconversion.numeric_converter_policy_classes.policy_rawconverter RawConverter] policy for details.
110 [section UDTs with numeric_cast]
112 In order to employ UDTs with `numeric_cast`, the user should define
113 a `numeric_cast_traits` specialization on the UDT for each conversion.
114 Here is an example of specializations for converting between the UDT
117 namespace boost { namespace numeric {
118 template <typename Source>
119 struct numeric_cast_traits<UDT, Source>
121 typedef conversion_traits<UDT, Source> conv_traits;
123 //! The following are required:
124 typedef YourOverflowHandlerPolicy overflow_policy;
125 typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
126 typedef YourFloat2IntRounderPolicy<Source> rounding_policy;
128 template <typename Target>
129 struct numeric_cast_traits<Target, UDT>
131 typedef conversion_traits<Target, UDT> conv_traits;
133 //! The following are required:
134 typedef YourOverflowHandlerPolicy overflow_policy;
135 typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
136 typedef YourFloat2IntRounderPolicy<UDT> rounding_policy;
138 }}//namespace boost::numeric;
140 These specializations are already defined with default values for the built-in
141 numeric types. It is possible to disable the generation of specializations for
142 built-in types by defining `BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS`.
143 For details on defining custom policies see [link boost_numericconversion.numeric_converter_policy_classes Converter Policies].
145 Here is a full example of how to define a custom UDT for use with `numeric_cast`:
147 //! Define a simple custom number
149 : boost::ordered_field_operators
152 , boost::ordered_field_operators2< Double, long double
153 , boost::ordered_field_operators2< Double, double
154 , boost::ordered_field_operators2< Double, float
155 , boost::ordered_field_operators2< Double, int
156 , boost::ordered_field_operators2< Double, unsigned int
157 , boost::ordered_field_operators2< Double, long
158 , boost::ordered_field_operators2< Double, unsigned long
159 , boost::ordered_field_operators2< Double, long long
160 , boost::ordered_field_operators2< Double, unsigned long long
161 , boost::ordered_field_operators2< Double, char
162 , boost::ordered_field_operators2< Double, unsigned char
163 , boost::ordered_field_operators2< Double, short
164 , boost::ordered_field_operators2< Double, unsigned short
165 > > > > > > > > > > > > > >
171 template <typename T>
172 explicit Double( T v )
173 : v(static_cast<double>(v))
176 template <typename T>
177 Double& operator= ( T t )
179 v = static_cast<double>(t);
183 bool operator < ( const Double& rhs ) const
188 template <typename T>
189 bool operator < ( T rhs ) const
191 return v < static_cast<double>(rhs);
194 bool operator > ( const Double& rhs ) const
199 template <typename T>
200 bool operator > ( T rhs ) const
202 return v > static_cast<double>(rhs);
205 bool operator ==( const Double& rhs ) const
210 template <typename T>
211 bool operator == ( T rhs ) const
213 return v == static_cast<double>(rhs);
216 bool operator !() const
221 Double operator -() const
226 Double& operator +=( const Double& t )
232 template <typename T>
233 Double& operator +=( T t )
235 v += static_cast<double>(t);
239 Double& operator -=( const Double& t )
245 template <typename T>
246 Double& operator -=( T t )
248 v -= static_cast<double>(t);
252 Double& operator *= ( const Double& factor )
258 template <typename T>
259 Double& operator *=( T t )
261 v *= static_cast<double>(t);
265 Double& operator /= (const Double& divisor)
271 template <typename T>
272 Double& operator /=( T t )
274 v /= static_cast<double>(t);
281 //! Define numeric_limits for the custom type.
285 class numeric_limits<Double> : public numeric_limits<double>
289 //! Limit our Double to a range of +/- 100.0
290 static Double (min)()
292 return Double(1.e-2);
295 static Double (max)()
300 static Double epsilon()
302 return Double( std::numeric_limits<double>::epsilon() );
307 //! Define range checking and overflow policies.
310 //! Define a custom range checker
311 template<typename Traits, typename OverFlowHandler>
314 typedef typename Traits::argument_type argument_type ;
315 typedef typename Traits::source_type S;
316 typedef typename Traits::target_type T;
318 //! Check range of integral types.
319 static boost::numeric::range_check_result out_of_range( argument_type s )
321 using namespace boost::numeric;
322 if( s > bounds<T>::highest() )
324 else if( s < bounds<T>::lowest() )
330 static void validate_range ( argument_type s )
332 BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded );
333 OverFlowHandler()( out_of_range(s) );
338 struct positive_overflow{};
339 struct negative_overflow{};
341 struct overflow_handler
343 void operator() ( boost::numeric::range_check_result r )
345 using namespace boost::numeric;
346 if( r == cNegOverflow )
347 throw negative_overflow() ;
348 else if( r == cPosOverflow )
349 throw positive_overflow() ;
353 //! Define a rounding policy and specialize on the custom type.
355 struct Ceil : boost::numeric::Ceil<S>{};
360 typedef Double source_type;
362 typedef Double const& argument_type;
364 static source_type nearbyint ( argument_type s )
366 #if !defined(BOOST_NO_STDC_NAMESPACE)
369 return Double( ceil(s.v) );
372 typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style;
375 //! Define a rounding policy and specialize on the custom type.
377 struct Trunc: boost::numeric::Trunc<S>{};
382 typedef Double source_type;
384 typedef Double const& argument_type;
386 static source_type nearbyint ( argument_type s )
388 #if !defined(BOOST_NO_STDC_NAMESPACE)
391 return Double( floor(s.v) );
394 typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style;
398 namespace boost { namespace numeric {
400 //! Define the numeric_cast_traits specializations on the custom type.
401 template <typename S>
402 struct numeric_cast_traits<Double, S>
404 typedef custom::overflow_handler overflow_policy;
405 typedef custom::range_checker
407 boost::numeric::conversion_traits<Double, S>
409 > range_checking_policy;
410 typedef boost::numeric::Trunc<S> rounding_policy;
413 template <typename T>
414 struct numeric_cast_traits<T, Double>
416 typedef custom::overflow_handler overflow_policy;
417 typedef custom::range_checker
419 boost::numeric::conversion_traits<T, Double>
421 > range_checking_policy;
422 typedef custom::Trunc<Double> rounding_policy;
425 //! Define the conversion from the custom type to built-in types and vice-versa.
427 struct raw_converter< conversion_traits< T, Double > >
429 static T low_level_convert ( const Double& n )
431 return static_cast<T>( n.v );
436 struct raw_converter< conversion_traits< Double, S > >
438 static Double low_level_convert ( const S& n )
443 }}//namespace boost::numeric;