Index: boost/numeric/conversion/cast.hpp =================================================================== --- boost/numeric/conversion/cast.hpp (revision 72716) +++ boost/numeric/conversion/cast.hpp (working copy) @@ -16,6 +16,7 @@ // 30 Oct 2001 Some fixes suggested by Daryle Walker (Fernando Cacciola) // 25 Oct 2001 Initial boostification (Fernando Cacciola) // 23 Jan 2004 Inital add to cvs (post review)s +// 22 Jun 2011 Added support for specializing cast policies via numeric_cast_traits (Brandon Kohn). // #ifndef BOOST_NUMERIC_CONVERSION_CAST_25OCT2001_HPP #define BOOST_NUMERIC_CONVERSION_CAST_25OCT2001_HPP @@ -30,22 +31,31 @@ #include #include +#include namespace boost { - template - inline - Target numeric_cast ( Source arg ) - { - typedef boost::numeric::converter Converter ; - return Converter::convert(arg); - } - - using numeric::bad_numeric_cast; - + template + inline Target numeric_cast( Source arg ) + { + typedef numeric::conversion_traits conv_traits; + typedef numeric::numeric_cast_traits cast_traits; + typedef boost::numeric::converter + < + Target, + Source, + conv_traits, + typename cast_traits::overflow_policy, + typename cast_traits::rounding_policy, + boost::numeric::raw_converter< conv_traits >, + typename cast_traits::range_checking_policy + > converter; + return converter::convert(arg); + } + + using numeric::bad_numeric_cast; } // namespace boost #endif - #endif Index: boost/numeric/conversion/numeric_cast_traits.hpp =================================================================== --- boost/numeric/conversion/numeric_cast_traits.hpp (revision 0) +++ boost/numeric/conversion/numeric_cast_traits.hpp (revision 0) @@ -0,0 +1,111 @@ +// +//! Copyright © 2011 +//! Brandon Kohn +// +// 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) +// +#ifndef BOOST_NUMERIC_CAST_TRAITS_HPP +#define BOOST_NUMERIC_CAST_TRAITS_HPP +#pragma once + +#include +#include + +namespace boost { namespace numeric { + + template + struct numeric_cast_traits + { + typedef def_overflow_handler overflow_policy; + typedef UseInternalRangeChecker range_checking_policy; + typedef Trunc< Source > rounding_policy; + }; + +#if !defined( BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS ) +#include + +//! Generate default traits for the specified source and target. +#define BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS(r, state) \ + template <> \ + struct numeric_cast_traits< \ + BOOST_PP_SEQ_ELEM( BOOST_PP_TUPLE_ELEM(4,0,state) \ + , BOOST_PP_TUPLE_ELEM(4,3,state) ) \ + , BOOST_PP_TUPLE_ELEM(4,2,state)> \ + { \ + typedef def_overflow_handler overflow_policy; \ + typedef UseInternalRangeChecker range_checking_policy; \ + typedef Trunc rounding_policy; \ + }; \ +/***/ + +#define BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL(r, state) \ + BOOST_PP_LESS \ + ( \ + BOOST_PP_TUPLE_ELEM(4,0,state) \ + , BOOST_PP_TUPLE_ELEM(4,1,state) \ + ) \ +/***/ + +#define BOOST_NUMERIC_CONVERSION_INC_OP(r, state) \ + ( \ + BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4,0,state)) \ + , BOOST_PP_TUPLE_ELEM(4,1,state) \ + , BOOST_PP_TUPLE_ELEM(4,2,state) \ + , BOOST_PP_TUPLE_ELEM(4,3,state) \ + ) \ +/***/ + +#define BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP(r, state) \ + BOOST_PP_FOR \ + ( \ + ( \ + 0 \ + , BOOST_PP_TUPLE_ELEM(4,1,state) \ + , BOOST_PP_SEQ_ELEM(BOOST_PP_TUPLE_ELEM(4,0,state),BOOST_PP_TUPLE_ELEM(4,2,state)) \ + , BOOST_PP_TUPLE_ELEM(4,2,state) \ + ) \ + , BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL \ + , BOOST_NUMERIC_CONVERSION_INC_OP \ + , BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS \ + ) \ +/***/ + +#define BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS(types) \ + BOOST_PP_FOR \ + ( \ + (0,BOOST_PP_SEQ_SIZE(types),types,_) \ + , BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL \ + , BOOST_NUMERIC_CONVERSION_INC_OP \ + , BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP \ + ) \ +/***/ + +//! Generate the specializations for the built-in types. +BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS +( + (boost::int8_t) + (boost::uint8_t) + (boost::int16_t) + (boost::uint16_t) + (boost::int32_t) + (boost::uint32_t) + (boost::int64_t) + (boost::uint64_t) + (float) + (double) + (long double) +) + +#undef BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS +#undef BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP +#undef BOOST_NUMERIC_CONVERSION_INC_OP +#undef BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL +#undef BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS + +#endif//!defined BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS + +}}//namespace boost::numeric; + +#endif//BOOST_NUMERIC_CAST_TRAITS_HPP Index: libs/numeric/conversion/doc/numeric_cast.qbk =================================================================== --- libs/numeric/conversion/doc/numeric_cast.qbk (revision 72716) +++ libs/numeric/conversion/doc/numeric_cast.qbk (working copy) @@ -34,7 +34,7 @@ aforementioned unsigned to unsigned) makes any code that may produce positive or negative overflows exposed to portability issues. -`numeric_cast` adheres to the rules for implicit conversions mandated by +By default `numeric_cast` adheres to the rules for implicit conversions mandated by the C++ Standard, such as truncating floating point types when converting to integral types. The implementation must guarantee that for a conversion to a type that can hold all possible values of the source type, there will @@ -43,17 +43,28 @@ [endsect] [section numeric_cast] - - template inline - typename boost::numeric::converter::result_type - numeric_cast ( Source arg ) + + template inline + Target numeric_cast( Source arg ) { - return boost::numeric::converter::convert(arg); + typedef conversion_traits conv_traits; + typedef numeric_cast_traits cast_traits; + typedef converter + < + Target, + Source, + conv_traits, + typename cast_traits::overflow_policy, + typename cast_traits::rounding_policy, + raw_converter, + typename cast_traits::range_checking_policy + > converter; + return converter::convert(arg); } `numeric_cast` returns the result of converting a value of type Source -to a value of type Target. If out-of-range is detected, an exception is -thrown (see +to a value of type Target. If out-of-range is detected, an overflow policy +is executed whose default behavior is to throw an an exception (see [link numeric_conversion_bad_numeric_cast bad_numeric_cast], [link numeric_conversion_negative_overflow negative_overflow] and [link numeric_conversion_possitive_overflow positive_overflow] @@ -61,6 +72,24 @@ [endsect] +[section numeric_cast_traits] + + template + struct numeric_cast_traits + { + typedef def_overflow_handler overflow_policy; + typedef UseInternalRangeChecker range_checking_policy; + typedef Trunc rounding_policy; + }; + +The behavior of `numeric_cast` may be tailored for custom numeric types through +the specialization of `numeric_cast_traits`. (see +[link boost_numericconversion.type_requirements_and_user_defined_types_support User Defined Types] +for details. +) + +[endsect] + [section Examples] The following example performs some typical conversions between numeric types: Index: libs/numeric/conversion/doc/requirements.qbk =================================================================== --- libs/numeric/conversion/doc/requirements.qbk (revision 72716) +++ libs/numeric/conversion/doc/requirements.qbk (working copy) @@ -94,17 +94,355 @@ 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.numeric_converter_policy_classes.policy_userrangechecker UserRangeChecker] policy for details. +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(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 +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 + struct numeric_cast_traits + { + typedef conversion_traits conv_traits; + + //! The following are required: + typedef YourOverflowHandlerPolicy overflow_policy; + typedef YourRangeCheckerPolicy range_checking_policy; + typedef YourFloat2IntRounderPolicy rounding_policy; + }; + template + struct numeric_cast_traits + { + typedef conversion_traits conv_traits; + + //! The following are required: + typedef YourOverflowHandlerPolicy overflow_policy; + typedef YourRangeCheckerPolicy range_checking_policy; + typedef YourFloat2IntRounderPolicy 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 + explicit Double( T v ) + : v(static_cast(v)) + {} + + template + Double& operator= ( T t ) + { + v = static_cast(t); + return *this; + } + + bool operator < ( const Double& rhs ) const + { + return v < rhs.v; + } + + template + bool operator < ( T rhs ) const + { + return v < static_cast(rhs); + } + + bool operator > ( const Double& rhs ) const + { + return v > rhs.v; + } + + template + bool operator > ( T rhs ) const + { + return v > static_cast(rhs); + } + + bool operator ==( const Double& rhs ) const + { + return v == rhs.v; + } + + template + bool operator == ( T rhs ) const + { + return v == static_cast(rhs); + } + + bool operator !() const + { + return v == 0; + } + + Double operator -() const + { + return Double(-v); + } + + Double& operator +=( const Double& t ) + { + v += t.v; + return *this; + } + + template + Double& operator +=( T t ) + { + v += static_cast(t); + return *this; + } + + Double& operator -=( const Double& t ) + { + v -= t.v; + return *this; + } + + template + Double& operator -=( T t ) + { + v -= static_cast(t); + return *this; + } + + Double& operator *= ( const Double& factor ) + { + v *= factor.v; + return *this; + } + + template + Double& operator *=( T t ) + { + v *= static_cast(t); + return *this; + } + + Double& operator /= (const Double& divisor) + { + v /= divisor.v; + return *this; + } + + template + Double& operator /=( T t ) + { + v /= static_cast(t); + return (*this); + } + + double v; + }; + + //! Define numeric_limits for the custom type. + namespace std + { + template<> + class numeric_limits : public numeric_limits + { + 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::epsilon() ); + } + }; + } + + //! Define range checking and overflow policies. + namespace custom + { + //! Define a custom range checker + template + 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::highest() ) + return cPosOverflow; + else if( s < bounds::lowest() ) + return cNegOverflow; + else + return cInRange; + } + + static void validate_range ( argument_type s ) + { + BOOST_STATIC_ASSERT( std::numeric_limits::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 + struct Ceil : boost::numeric::Ceil{}; + + template<> + struct Ceil + { + 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 + struct Trunc: boost::numeric::Trunc{}; + + template<> + struct Trunc + { + 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 + struct numeric_cast_traits + { + typedef custom::overflow_handler overflow_policy; + typedef custom::range_checker + < + boost::numeric::conversion_traits + , overflow_policy + > range_checking_policy; + typedef boost::numeric::Trunc rounding_policy; + }; + + template + struct numeric_cast_traits + { + typedef custom::overflow_handler overflow_policy; + typedef custom::range_checker + < + boost::numeric::conversion_traits + , overflow_policy + > range_checking_policy; + typedef custom::Trunc rounding_policy; + }; + + //! Define the conversion from the custom type to built-in types and vice-versa. + template + struct raw_converter< conversion_traits< T, Double > > + { + static T low_level_convert ( const Double& n ) + { + return static_cast( n.v ); + } + }; + + template + struct raw_converter< conversion_traits< Double, S > > + { + static Double low_level_convert ( const S& n ) + { + return Double(n); + } + }; + }}//namespace boost::numeric; + [endsect] +[endsect] + Index: libs/numeric/conversion/test/Jamfile.v2 =================================================================== --- libs/numeric/conversion/test/Jamfile.v2 (revision 72716) +++ libs/numeric/conversion/test/Jamfile.v2 (working copy) @@ -13,5 +13,6 @@ [ run udt_support_test.cpp ] [ run numeric_cast_test.cpp ] [ run udt_example_0.cpp ] + [ run numeric_cast_traits_test.cpp ] ; Index: libs/numeric/conversion/test/numeric_cast_traits_test.cpp =================================================================== --- libs/numeric/conversion/test/numeric_cast_traits_test.cpp (revision 0) +++ libs/numeric/conversion/test/numeric_cast_traits_test.cpp (revision 0) @@ -0,0 +1,366 @@ +// +//! Copyright © 2011 +//! Brandon Kohn +// +// 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) +// + +#include +#include +#include +#include +#include +#include + +//! 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 + explicit Double( T v ) + : v(static_cast(v)) + {} + + template + Double& operator= ( T t ) + { + v = static_cast(t); + return *this; + } + + bool operator < ( const Double& rhs ) const + { + return v < rhs.v; + } + + template + bool operator < ( T rhs ) const + { + return v < static_cast(rhs); + } + + bool operator > ( const Double& rhs ) const + { + return v > rhs.v; + } + + template + bool operator > ( T rhs ) const + { + return v > static_cast(rhs); + } + + bool operator ==( const Double& rhs ) const + { + return v == rhs.v; + } + + template + bool operator == ( T rhs ) const + { + return v == static_cast(rhs); + } + + bool operator !() const + { + return v == 0; + } + + Double operator -() const + { + return Double(-v); + } + + Double& operator +=( const Double& t ) + { + v += t.v; + return *this; + } + + template + Double& operator +=( T t ) + { + v += static_cast(t); + return *this; + } + + Double& operator -=( const Double& t ) + { + v -= t.v; + return *this; + } + + template + Double& operator -=( T t ) + { + v -= static_cast(t); + return *this; + } + + Double& operator *= ( const Double& factor ) + { + v *= factor.v; + return *this; + } + + template + Double& operator *=( T t ) + { + v *= static_cast(t); + return *this; + } + + Double& operator /= (const Double& divisor) + { + v /= divisor.v; + return *this; + } + + template + Double& operator /=( T t ) + { + v /= static_cast(t); + return (*this); + } + + double v; +}; + +//! Define numeric_limits for the custom type. +namespace std +{ + template<> + class numeric_limits< Double > : public numeric_limits + { + 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::epsilon() ); + } + }; +} + +//! Define range checking and overflow policies. +namespace custom +{ + //! Define a custom range checker + template + 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::highest() ) + return cPosOverflow; + else if( s < bounds::lowest() ) + return cNegOverflow; + else + return cInRange; + } + + static void validate_range ( argument_type s ) + { + BOOST_STATIC_ASSERT( std::numeric_limits::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 + struct Ceil : boost::numeric::Ceil{}; + + template<> + struct Ceil + { + 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 + struct Trunc: boost::numeric::Trunc{}; + + template<> + struct Trunc + { + 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 + struct numeric_cast_traits + { + typedef custom::overflow_handler overflow_policy; + typedef custom::range_checker + < + boost::numeric::conversion_traits + , overflow_policy + > range_checking_policy; + typedef boost::numeric::Trunc rounding_policy; + }; + + template + struct numeric_cast_traits + { + typedef custom::overflow_handler overflow_policy; + typedef custom::range_checker + < + boost::numeric::conversion_traits + , overflow_policy + > range_checking_policy; + typedef custom::Trunc rounding_policy; + }; + + //! Define the conversion from the custom type to built-in types and vice-versa. + template + struct raw_converter< conversion_traits< T, Double > > + { + static T low_level_convert ( const Double& n ) + { + return static_cast( n.v ); + } + }; + + template + struct raw_converter< conversion_traits< Double, S > > + { + static Double low_level_convert ( const S& n ) + { + return Double(n); + } + }; +}}//namespace boost::numeric; + +#define BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( CastCode ) \ + try { CastCode; BOOST_CHECK( false ); } \ + catch( custom::positive_overflow& ){} \ + catch(...){ BOOST_CHECK( false ); } \ +/***/ + +#define BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( CastCode ) \ + try { CastCode; BOOST_CHECK( false ); } \ + catch( custom::negative_overflow& ){} \ + catch(...){ BOOST_CHECK( false ); } \ +/***/ + +struct test_cast_traits +{ + template + void operator()(T) const + { + Double d = boost::numeric_cast( static_cast(50) ); + BOOST_CHECK( d.v == 50. ); + T v = boost::numeric_cast( d ); + BOOST_CHECK( v == 50 ); + } +}; + +void test_numeric_cast_traits() +{ + using namespace boost; + using namespace boost::numeric; + typedef mpl::vector< int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, float, double, long double > types; + mpl::for_each( test_cast_traits() ); + + //! Check overflow handler. + Double d( 56.0 ); + BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( d = numeric_cast( 101 ) ); + BOOST_CHECK( d.v == 56. ); + BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( d = numeric_cast( -101 ) ); + BOOST_CHECK( d.v == 56.); + + //! Check custom round policy. + d = 5.9; + int five = boost::numeric_cast( d ); + BOOST_CHECK( five == 5 ); +} + +int test_main( int argc, char * argv[] ) +{ + test_numeric_cast_traits(); + return 0; +} + +#undef BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW +#undef BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW