507d157d10
[SVN r73675]
449 lines
14 KiB
Plaintext
449 lines
14 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 Type Requirements and User-defined-types support]
|
|
|
|
[section Type Requirements]
|
|
|
|
Both arithmetic (built-in) and user-defined numeric types require proper
|
|
specialization of `std::numeric_limits<>` (that is, with (in-class) integral
|
|
constants).
|
|
|
|
The library uses `std::numeric_limits<T>::is_specialized` to detect whether
|
|
the type is builtin or user defined, and `std::numeric_limits<T>::is_integer`,
|
|
`std::numeric_limits<T>::is_signed` to detect whether the type is integer
|
|
or floating point; and whether it is signed/unsigned.
|
|
|
|
The default `Float2IntRounder` policies uses unqualified calls to functions
|
|
`floor()` and `ceil()`; but the standard functions are introduced in scope
|
|
by a using directive:
|
|
|
|
using std::floor ; return floor(s);
|
|
|
|
Therefore, for builtin arithmetic types, the std functions will be used.
|
|
User defined types should provide overloaded versions of these functions in
|
|
order to use the default rounder policies. If these overloads are defined
|
|
within a user namespace argument dependent lookup (ADL) should find them,
|
|
but if your compiler has a weak ADL you might need to put these functions
|
|
some place else or write your own rounder policy.
|
|
|
|
The default `Trunc<>` rounder policy needs to determine if the source value
|
|
is positive or not, and for this it evaluates the expression
|
|
`s < static_cast<S>(0)`. Therefore, user defined types require a visible
|
|
`operator<` in order to use the `Trunc<>` policy (the default).
|
|
|
|
|
|
[endsect]
|
|
|
|
[section UDT's special semantics]
|
|
|
|
[heading Conversion Traits]
|
|
|
|
If a User Defined Type is involved in a conversion, it is ['assumed] that
|
|
the UDT has [link boost_numericconversion.definitions.range_and_precision wider range]
|
|
than any built-in type, and consequently the values
|
|
of some `converter_traits<>` members are hardwired regardless of the reality.
|
|
The following table summarizes this:
|
|
|
|
* `Target=`['UDT] and `Source=`['built-in]
|
|
* `subranged=false`
|
|
* `supertype=Target`
|
|
* `subtype=Source`
|
|
* `Target=`['built-in] and `Source=`['UDT]
|
|
* `subranged=true`
|
|
* `supertype=Source`
|
|
* `subtype=Target`
|
|
|
|
* `Target=`['UDT] and `Source=`['UDT]
|
|
* `subranged=false`
|
|
* `supertype=Target`
|
|
* `subtype=Source`
|
|
|
|
|
|
The `Traits` member `udt_mixture` can be used to detect whether a UDT is involved
|
|
and to infer the validity of the other members as shown above.
|
|
|
|
[heading Range Checking]
|
|
|
|
Because User Defined Numeric Types might have peculiar ranges (such as an
|
|
unbounded range), this library does not attempt to supply a meaningful range
|
|
checking logic when UDTs are involved in a conversion. Therefore, if either
|
|
Target or Source are not built-in types, the bundled range checking of the
|
|
`converter<>` function object is automatically disabled. However, it is possible
|
|
to supply a user-defined range-checker. See
|
|
[link boost_numericconversion.type_requirements_and_user_defined_types_support.special_policies Special Policies]
|
|
|
|
[endsect]
|
|
|
|
[section Special Policies]
|
|
|
|
There are two components of the `converter<>` class that might require special
|
|
behavior if User Defined Numeric Types are involved: the Range Checking and the
|
|
Raw Conversion.
|
|
|
|
When both Target and Source are built-in types, the converter class uses an internal
|
|
range checking logic which is optimized and customized for the combined properties
|
|
of the types.
|
|
|
|
However, this internal logic is disabled when either type is User Defined.
|
|
In this case, the user can specify an ['external] range checking policy which will be
|
|
used in place of the internal code. See
|
|
[link boost_numericconversion.type_requirements_and_user_defined_types_support.udts_with_numeric_cast numeric_cast_traits]
|
|
for details on using UDTs with `numeric_cast`.
|
|
|
|
The converter class performs the actual conversion using a Raw Converter policy.
|
|
The default raw converter simply performs a `static_cast<Target>(source)`.
|
|
|
|
However, if the a UDT is involved, the `static_cast` might not work. In this case,
|
|
the user can implement and pass a different raw converter policy.
|
|
See [link boost_numericconversion.numeric_converter_policy_classes.policy_rawconverter RawConverter] policy for details.
|
|
|
|
[endsect]
|
|
|
|
[section UDTs with numeric_cast]
|
|
|
|
In order to employ UDTs with `numeric_cast`, the user should define
|
|
a `numeric_cast_traits` specialization on the UDT for each conversion.
|
|
Here is an example of specializations for converting between the UDT
|
|
and any other type:
|
|
|
|
namespace boost { namespace numeric {
|
|
template <typename Source>
|
|
struct numeric_cast_traits<UDT, Source>
|
|
{
|
|
typedef conversion_traits<UDT, Source> conv_traits;
|
|
|
|
//! The following are required:
|
|
typedef YourOverflowHandlerPolicy overflow_policy;
|
|
typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
|
|
typedef YourFloat2IntRounderPolicy<Source> rounding_policy;
|
|
};
|
|
template <typename Target>
|
|
struct numeric_cast_traits<Target, UDT>
|
|
{
|
|
typedef conversion_traits<Target, UDT> conv_traits;
|
|
|
|
//! The following are required:
|
|
typedef YourOverflowHandlerPolicy overflow_policy;
|
|
typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
|
|
typedef YourFloat2IntRounderPolicy<UDT> rounding_policy;
|
|
};
|
|
}}//namespace boost::numeric;
|
|
|
|
These specializations are already defined with default values for the built-in
|
|
numeric types. It is possible to disable the generation of specializations for
|
|
built-in types by defining `BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS`.
|
|
For details on defining custom policies see [link boost_numericconversion.numeric_converter_policy_classes Converter Policies].
|
|
|
|
Here is a full example of how to define a custom UDT for use with `numeric_cast`:
|
|
|
|
//! Define a simple custom number
|
|
struct Double
|
|
: boost::ordered_field_operators
|
|
<
|
|
Double
|
|
, boost::ordered_field_operators2< Double, long double
|
|
, boost::ordered_field_operators2< Double, double
|
|
, boost::ordered_field_operators2< Double, float
|
|
, boost::ordered_field_operators2< Double, int
|
|
, boost::ordered_field_operators2< Double, unsigned int
|
|
, boost::ordered_field_operators2< Double, long
|
|
, boost::ordered_field_operators2< Double, unsigned long
|
|
, boost::ordered_field_operators2< Double, long long
|
|
, boost::ordered_field_operators2< Double, unsigned long long
|
|
, boost::ordered_field_operators2< Double, char
|
|
, boost::ordered_field_operators2< Double, unsigned char
|
|
, boost::ordered_field_operators2< Double, short
|
|
, boost::ordered_field_operators2< Double, unsigned short
|
|
> > > > > > > > > > > > > >
|
|
{
|
|
Double()
|
|
: v(0)
|
|
{}
|
|
|
|
template <typename T>
|
|
explicit Double( T v )
|
|
: v(static_cast<double>(v))
|
|
{}
|
|
|
|
template <typename T>
|
|
Double& operator= ( T t )
|
|
{
|
|
v = static_cast<double>(t);
|
|
return *this;
|
|
}
|
|
|
|
bool operator < ( const Double& rhs ) const
|
|
{
|
|
return v < rhs.v;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator < ( T rhs ) const
|
|
{
|
|
return v < static_cast<double>(rhs);
|
|
}
|
|
|
|
bool operator > ( const Double& rhs ) const
|
|
{
|
|
return v > rhs.v;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator > ( T rhs ) const
|
|
{
|
|
return v > static_cast<double>(rhs);
|
|
}
|
|
|
|
bool operator ==( const Double& rhs ) const
|
|
{
|
|
return v == rhs.v;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator == ( T rhs ) const
|
|
{
|
|
return v == static_cast<double>(rhs);
|
|
}
|
|
|
|
bool operator !() const
|
|
{
|
|
return v == 0;
|
|
}
|
|
|
|
Double operator -() const
|
|
{
|
|
return Double(-v);
|
|
}
|
|
|
|
Double& operator +=( const Double& t )
|
|
{
|
|
v += t.v;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
Double& operator +=( T t )
|
|
{
|
|
v += static_cast<double>(t);
|
|
return *this;
|
|
}
|
|
|
|
Double& operator -=( const Double& t )
|
|
{
|
|
v -= t.v;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
Double& operator -=( T t )
|
|
{
|
|
v -= static_cast<double>(t);
|
|
return *this;
|
|
}
|
|
|
|
Double& operator *= ( const Double& factor )
|
|
{
|
|
v *= factor.v;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
Double& operator *=( T t )
|
|
{
|
|
v *= static_cast<double>(t);
|
|
return *this;
|
|
}
|
|
|
|
Double& operator /= (const Double& divisor)
|
|
{
|
|
v /= divisor.v;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
Double& operator /=( T t )
|
|
{
|
|
v /= static_cast<double>(t);
|
|
return (*this);
|
|
}
|
|
|
|
double v;
|
|
};
|
|
|
|
//! Define numeric_limits for the custom type.
|
|
namespace std
|
|
{
|
|
template<>
|
|
class numeric_limits<Double> : public numeric_limits<double>
|
|
{
|
|
public:
|
|
|
|
//! Limit our Double to a range of +/- 100.0
|
|
static Double (min)()
|
|
{
|
|
return Double(1.e-2);
|
|
}
|
|
|
|
static Double (max)()
|
|
{
|
|
return Double(1.e2);
|
|
}
|
|
|
|
static Double epsilon()
|
|
{
|
|
return Double( std::numeric_limits<double>::epsilon() );
|
|
}
|
|
};
|
|
}
|
|
|
|
//! Define range checking and overflow policies.
|
|
namespace custom
|
|
{
|
|
//! Define a custom range checker
|
|
template<typename Traits, typename OverFlowHandler>
|
|
struct range_checker
|
|
{
|
|
typedef typename Traits::argument_type argument_type ;
|
|
typedef typename Traits::source_type S;
|
|
typedef typename Traits::target_type T;
|
|
|
|
//! Check range of integral types.
|
|
static boost::numeric::range_check_result out_of_range( argument_type s )
|
|
{
|
|
using namespace boost::numeric;
|
|
if( s > bounds<T>::highest() )
|
|
return cPosOverflow;
|
|
else if( s < bounds<T>::lowest() )
|
|
return cNegOverflow;
|
|
else
|
|
return cInRange;
|
|
}
|
|
|
|
static void validate_range ( argument_type s )
|
|
{
|
|
BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded );
|
|
OverFlowHandler()( out_of_range(s) );
|
|
}
|
|
};
|
|
|
|
//! Overflow handler
|
|
struct positive_overflow{};
|
|
struct negative_overflow{};
|
|
|
|
struct overflow_handler
|
|
{
|
|
void operator() ( boost::numeric::range_check_result r )
|
|
{
|
|
using namespace boost::numeric;
|
|
if( r == cNegOverflow )
|
|
throw negative_overflow() ;
|
|
else if( r == cPosOverflow )
|
|
throw positive_overflow() ;
|
|
}
|
|
};
|
|
|
|
//! Define a rounding policy and specialize on the custom type.
|
|
template<class S>
|
|
struct Ceil : boost::numeric::Ceil<S>{};
|
|
|
|
template<>
|
|
struct Ceil<Double>
|
|
{
|
|
typedef Double source_type;
|
|
|
|
typedef Double const& argument_type;
|
|
|
|
static source_type nearbyint ( argument_type s )
|
|
{
|
|
#if !defined(BOOST_NO_STDC_NAMESPACE)
|
|
using std::ceil ;
|
|
#endif
|
|
return Double( ceil(s.v) );
|
|
}
|
|
|
|
typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style;
|
|
};
|
|
|
|
//! Define a rounding policy and specialize on the custom type.
|
|
template<class S>
|
|
struct Trunc: boost::numeric::Trunc<S>{};
|
|
|
|
template<>
|
|
struct Trunc<Double>
|
|
{
|
|
typedef Double source_type;
|
|
|
|
typedef Double const& argument_type;
|
|
|
|
static source_type nearbyint ( argument_type s )
|
|
{
|
|
#if !defined(BOOST_NO_STDC_NAMESPACE)
|
|
using std::floor;
|
|
#endif
|
|
return Double( floor(s.v) );
|
|
}
|
|
|
|
typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style;
|
|
};
|
|
}//namespace custom;
|
|
|
|
namespace boost { namespace numeric {
|
|
|
|
//! Define the numeric_cast_traits specializations on the custom type.
|
|
template <typename S>
|
|
struct numeric_cast_traits<Double, S>
|
|
{
|
|
typedef custom::overflow_handler overflow_policy;
|
|
typedef custom::range_checker
|
|
<
|
|
boost::numeric::conversion_traits<Double, S>
|
|
, overflow_policy
|
|
> range_checking_policy;
|
|
typedef boost::numeric::Trunc<S> rounding_policy;
|
|
};
|
|
|
|
template <typename T>
|
|
struct numeric_cast_traits<T, Double>
|
|
{
|
|
typedef custom::overflow_handler overflow_policy;
|
|
typedef custom::range_checker
|
|
<
|
|
boost::numeric::conversion_traits<T, Double>
|
|
, overflow_policy
|
|
> range_checking_policy;
|
|
typedef custom::Trunc<Double> rounding_policy;
|
|
};
|
|
|
|
//! Define the conversion from the custom type to built-in types and vice-versa.
|
|
template<typename T>
|
|
struct raw_converter< conversion_traits< T, Double > >
|
|
{
|
|
static T low_level_convert ( const Double& n )
|
|
{
|
|
return static_cast<T>( n.v );
|
|
}
|
|
};
|
|
|
|
template<typename S>
|
|
struct raw_converter< conversion_traits< Double, S > >
|
|
{
|
|
static Double low_level_convert ( const S& n )
|
|
{
|
|
return Double(n);
|
|
}
|
|
};
|
|
}}//namespace boost::numeric;
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|