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 Type Requirements and User-defined-types support] 12 13[section Type Requirements] 14 15Both arithmetic (built-in) and user-defined numeric types require proper 16specialization of `std::numeric_limits<>` (that is, with (in-class) integral 17constants). 18 19The library uses `std::numeric_limits<T>::is_specialized` to detect whether 20the 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 22or floating point; and whether it is signed/unsigned. 23 24The default `Float2IntRounder` policies uses unqualified calls to functions 25`floor()` and `ceil()`; but the standard functions are introduced in scope 26by a using directive: 27 28 using std::floor ; return floor(s); 29 30Therefore, for builtin arithmetic types, the std functions will be used. 31User defined types should provide overloaded versions of these functions in 32order to use the default rounder policies. If these overloads are defined 33within a user namespace argument dependent lookup (ADL) should find them, 34but if your compiler has a weak ADL you might need to put these functions 35some place else or write your own rounder policy. 36 37The default `Trunc<>` rounder policy needs to determine if the source value 38is 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). 41 42 43[endsect] 44 45[section UDT's special semantics] 46 47[heading Conversion Traits] 48 49If a User Defined Type is involved in a conversion, it is ['assumed] that 50the UDT has [link boost_numericconversion.definitions.range_and_precision wider range] 51than any built-in type, and consequently the values 52of some `converter_traits<>` members are hardwired regardless of the reality. 53The following table summarizes this: 54 55* `Target=`['UDT] and `Source=`['built-in] 56 * `subranged=false` 57 * `supertype=Target` 58 * `subtype=Source` 59* `Target=`['built-in] and `Source=`['UDT] 60 * `subranged=true` 61 * `supertype=Source` 62 * `subtype=Target` 63 64* `Target=`['UDT] and `Source=`['UDT] 65 * `subranged=false` 66 * `supertype=Target` 67 * `subtype=Source` 68 69 70The `Traits` member `udt_mixture` can be used to detect whether a UDT is involved 71and to infer the validity of the other members as shown above. 72 73[heading Range Checking] 74 75Because User Defined Numeric Types might have peculiar ranges (such as an 76unbounded range), this library does not attempt to supply a meaningful range 77checking logic when UDTs are involved in a conversion. Therefore, if either 78Target or Source are not built-in types, the bundled range checking of the 79`converter<>` function object is automatically disabled. However, it is possible 80to supply a user-defined range-checker. See 81[link boost_numericconversion.type_requirements_and_user_defined_types_support.special_policies Special Policies] 82 83[endsect] 84 85[section Special Policies] 86 87There are two components of the `converter<>` class that might require special 88behavior if User Defined Numeric Types are involved: the Range Checking and the 89Raw Conversion. 90 91When both Target and Source are built-in types, the converter class uses an internal 92range checking logic which is optimized and customized for the combined properties 93of the types. 94 95However, this internal logic is disabled when either type is User Defined. 96In this case, the user can specify an ['external] range checking policy which will be 97used 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] 99for details on using UDTs with `numeric_cast`. 100 101The converter class performs the actual conversion using a Raw Converter policy. 102The default raw converter simply performs a `static_cast<Target>(source)`. 103 104However, if the a UDT is involved, the `static_cast` might not work. In this case, 105the user can implement and pass a different raw converter policy. 106See [link boost_numericconversion.numeric_converter_policy_classes.policy_rawconverter RawConverter] policy for details. 107 108[endsect] 109 110[section UDTs with numeric_cast] 111 112In order to employ UDTs with `numeric_cast`, the user should define 113a `numeric_cast_traits` specialization on the UDT for each conversion. 114Here is an example of specializations for converting between the UDT 115and any other type: 116 117 namespace boost { namespace numeric { 118 template <typename Source> 119 struct numeric_cast_traits<UDT, Source> 120 { 121 typedef conversion_traits<UDT, Source> conv_traits; 122 123 //! The following are required: 124 typedef YourOverflowHandlerPolicy overflow_policy; 125 typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy; 126 typedef YourFloat2IntRounderPolicy<Source> rounding_policy; 127 }; 128 template <typename Target> 129 struct numeric_cast_traits<Target, UDT> 130 { 131 typedef conversion_traits<Target, UDT> conv_traits; 132 133 //! The following are required: 134 typedef YourOverflowHandlerPolicy overflow_policy; 135 typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy; 136 typedef YourFloat2IntRounderPolicy<UDT> rounding_policy; 137 }; 138 }}//namespace boost::numeric; 139 140These specializations are already defined with default values for the built-in 141numeric types. It is possible to disable the generation of specializations for 142built-in types by defining `BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS`. 143For details on defining custom policies see [link boost_numericconversion.numeric_converter_policy_classes Converter Policies]. 144 145Here is a full example of how to define a custom UDT for use with `numeric_cast`: 146 147 //! Define a simple custom number 148 struct Double 149 : boost::ordered_field_operators 150 < 151 Double 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 > > > > > > > > > > > > > > 166 { 167 Double() 168 : v(0) 169 {} 170 171 template <typename T> 172 explicit Double( T v ) 173 : v(static_cast<double>(v)) 174 {} 175 176 template <typename T> 177 Double& operator= ( T t ) 178 { 179 v = static_cast<double>(t); 180 return *this; 181 } 182 183 bool operator < ( const Double& rhs ) const 184 { 185 return v < rhs.v; 186 } 187 188 template <typename T> 189 bool operator < ( T rhs ) const 190 { 191 return v < static_cast<double>(rhs); 192 } 193 194 bool operator > ( const Double& rhs ) const 195 { 196 return v > rhs.v; 197 } 198 199 template <typename T> 200 bool operator > ( T rhs ) const 201 { 202 return v > static_cast<double>(rhs); 203 } 204 205 bool operator ==( const Double& rhs ) const 206 { 207 return v == rhs.v; 208 } 209 210 template <typename T> 211 bool operator == ( T rhs ) const 212 { 213 return v == static_cast<double>(rhs); 214 } 215 216 bool operator !() const 217 { 218 return v == 0; 219 } 220 221 Double operator -() const 222 { 223 return Double(-v); 224 } 225 226 Double& operator +=( const Double& t ) 227 { 228 v += t.v; 229 return *this; 230 } 231 232 template <typename T> 233 Double& operator +=( T t ) 234 { 235 v += static_cast<double>(t); 236 return *this; 237 } 238 239 Double& operator -=( const Double& t ) 240 { 241 v -= t.v; 242 return *this; 243 } 244 245 template <typename T> 246 Double& operator -=( T t ) 247 { 248 v -= static_cast<double>(t); 249 return *this; 250 } 251 252 Double& operator *= ( const Double& factor ) 253 { 254 v *= factor.v; 255 return *this; 256 } 257 258 template <typename T> 259 Double& operator *=( T t ) 260 { 261 v *= static_cast<double>(t); 262 return *this; 263 } 264 265 Double& operator /= (const Double& divisor) 266 { 267 v /= divisor.v; 268 return *this; 269 } 270 271 template <typename T> 272 Double& operator /=( T t ) 273 { 274 v /= static_cast<double>(t); 275 return (*this); 276 } 277 278 double v; 279 }; 280 281 //! Define numeric_limits for the custom type. 282 namespace std 283 { 284 template<> 285 class numeric_limits<Double> : public numeric_limits<double> 286 { 287 public: 288 289 //! Limit our Double to a range of +/- 100.0 290 static Double (min)() 291 { 292 return Double(1.e-2); 293 } 294 295 static Double (max)() 296 { 297 return Double(1.e2); 298 } 299 300 static Double epsilon() 301 { 302 return Double( std::numeric_limits<double>::epsilon() ); 303 } 304 }; 305 } 306 307 //! Define range checking and overflow policies. 308 namespace custom 309 { 310 //! Define a custom range checker 311 template<typename Traits, typename OverFlowHandler> 312 struct range_checker 313 { 314 typedef typename Traits::argument_type argument_type ; 315 typedef typename Traits::source_type S; 316 typedef typename Traits::target_type T; 317 318 //! Check range of integral types. 319 static boost::numeric::range_check_result out_of_range( argument_type s ) 320 { 321 using namespace boost::numeric; 322 if( s > bounds<T>::highest() ) 323 return cPosOverflow; 324 else if( s < bounds<T>::lowest() ) 325 return cNegOverflow; 326 else 327 return cInRange; 328 } 329 330 static void validate_range ( argument_type s ) 331 { 332 BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded ); 333 OverFlowHandler()( out_of_range(s) ); 334 } 335 }; 336 337 //! Overflow handler 338 struct positive_overflow{}; 339 struct negative_overflow{}; 340 341 struct overflow_handler 342 { 343 void operator() ( boost::numeric::range_check_result r ) 344 { 345 using namespace boost::numeric; 346 if( r == cNegOverflow ) 347 throw negative_overflow() ; 348 else if( r == cPosOverflow ) 349 throw positive_overflow() ; 350 } 351 }; 352 353 //! Define a rounding policy and specialize on the custom type. 354 template<class S> 355 struct Ceil : boost::numeric::Ceil<S>{}; 356 357 template<> 358 struct Ceil<Double> 359 { 360 typedef Double source_type; 361 362 typedef Double const& argument_type; 363 364 static source_type nearbyint ( argument_type s ) 365 { 366 #if !defined(BOOST_NO_STDC_NAMESPACE) 367 using std::ceil ; 368 #endif 369 return Double( ceil(s.v) ); 370 } 371 372 typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style; 373 }; 374 375 //! Define a rounding policy and specialize on the custom type. 376 template<class S> 377 struct Trunc: boost::numeric::Trunc<S>{}; 378 379 template<> 380 struct Trunc<Double> 381 { 382 typedef Double source_type; 383 384 typedef Double const& argument_type; 385 386 static source_type nearbyint ( argument_type s ) 387 { 388 #if !defined(BOOST_NO_STDC_NAMESPACE) 389 using std::floor; 390 #endif 391 return Double( floor(s.v) ); 392 } 393 394 typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style; 395 }; 396 }//namespace custom; 397 398 namespace boost { namespace numeric { 399 400 //! Define the numeric_cast_traits specializations on the custom type. 401 template <typename S> 402 struct numeric_cast_traits<Double, S> 403 { 404 typedef custom::overflow_handler overflow_policy; 405 typedef custom::range_checker 406 < 407 boost::numeric::conversion_traits<Double, S> 408 , overflow_policy 409 > range_checking_policy; 410 typedef boost::numeric::Trunc<S> rounding_policy; 411 }; 412 413 template <typename T> 414 struct numeric_cast_traits<T, Double> 415 { 416 typedef custom::overflow_handler overflow_policy; 417 typedef custom::range_checker 418 < 419 boost::numeric::conversion_traits<T, Double> 420 , overflow_policy 421 > range_checking_policy; 422 typedef custom::Trunc<Double> rounding_policy; 423 }; 424 425 //! Define the conversion from the custom type to built-in types and vice-versa. 426 template<typename T> 427 struct raw_converter< conversion_traits< T, Double > > 428 { 429 static T low_level_convert ( const Double& n ) 430 { 431 return static_cast<T>( n.v ); 432 } 433 }; 434 435 template<typename S> 436 struct raw_converter< conversion_traits< Double, S > > 437 { 438 static Double low_level_convert ( const S& n ) 439 { 440 return Double(n); 441 } 442 }; 443 }}//namespace boost::numeric; 444 445[endsect] 446 447[endsect] 448 449