• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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