|
Boost : |
From: Dill, John (john-dill_at_[hidden])
Date: 2004-04-21 09:20:46
"Fernando Cacciola" <fernando_cacciola_at_[hidden]> wrote in message news:<c64iag$bes$1_at_[hidden]>...
>
> "David Abrahams" <dave_at_[hidden]> escribió en el mensaje
> news:u3c6ywa5w.fsf_at_boost-consulting.com...
> > "Dill, John" <john-dill_at_[hidden]> writes:
> >
> > > I am wondering about the use-case of numeric_cast in this sample.
> > >
> > > unsigned char uchar_max = std::numeric_limits<unsigned char>::max();
> > > char schar_value = 0;
> > >
> > > try {
> > > schar_value = boost::numeric_cast<char>( uchar_max );
> > > }
> > > catch ( boost::bad_numeric_cast )
> > > { std::cout << "Overflow occurred..." << std::endl; }
> > >
> > > When I execute this sample, I don't get the exception. What's the
> > > background on this behavior? I'm using gcc 3.3.1.
> >
> > FWIW, there are known problems with numeric_cast, but a numeric
> > conversion library that replaces the existing implementation has been
> > accepted into Boost. We are just waiting for Fernando Cacciola to
> > check it in. Fernando?
> >
> Indeed. The accepted numeric conversions library handles this case properly
> (throwing).
> Right now I'm technically on vacation until next Monday. I'll start working
> with the review comments right next week. I'll check it in on CVS after I
> made the neccesary changes.
>
> Anyway, users can download the review version from here:
>
> http://personales.ciudad.com.ar/fernando_cacciola/numeric_conversions.zip
>
> or
>
> http://groups.yahoo.com/group/boost/files/numeric_conversions.zip
>
>
> Fernando Cacciola
Thanks. Well, I didn't know this was out there so I wrote my own numeric_cast which works for those cases I described. It's not boost oriented, but all of the concepts should be convertible to mpl. Maybe it will be useful to someone.
Best,
John
/*!
* \file numeric_cast.hpp
* \brief A cast which protects against silent underflow or overflow casts.
*/
#include <uiro/type/ct_if.hpp>
#include <uiro/type/typelist.hpp>
#include <uiro/utility/limits.hpp>
namespace uiro {
//! Exception used to indicate underflow in a numeric cast.
class bad_numeric_cast
: public std::bad_cast
{
public:
virtual const char* what() const throw()
{ return "bad numeric cast"; }
};
//! Exception used to indicate underflow in a numeric cast.
class numeric_cast_underflow
: public bad_numeric_cast
{
public:
virtual const char* what() const throw()
{ return "underflow in numeric_cast"; }
};
//! Exception used to indicate overflow in a numeric cast.
class numeric_cast_overflow
: public bad_numeric_cast
{
public:
virtual const char* what() const throw()
{ return "overflow in numeric_cast"; }
};
namespace internal {
//! Selects the type with the largest minimum value.
template <typename T1, typename T2>
struct promote_min_traits {
typedef TYPELIST_10(unsigned char, unsigned short, unsigned int, unsigned long, char, short, int, long, float, double) promote_order_typelist;
enum { index1 = uiro::type::index_of<promote_order_typelist, T1>::value };
enum { index2 = uiro::type::index_of<promote_order_typelist, T2>::value };
typedef typename uiro::type::ct_if< uiro::type::greater_than_equal<index1,index2>::result, T1, T2>::result result;
};
//! Selects the type with the largest maximum value.
template <typename T1, typename T2>
struct promote_max_traits {
// May run into issues if sizeof(int) != sizeof(long)
typedef TYPELIST_10(char, unsigned char, short, unsigned short, int, long, unsigned int, unsigned long, float, double) promote_order_typelist;
enum { index1 = uiro::type::index_of<promote_order_typelist, T1>::value };
enum { index2 = uiro::type::index_of<promote_order_typelist, T2>::value };
typedef typename uiro::type::ct_if< uiro::type::greater_than_equal<index1,index2>::result, T1, T2>::result result;
};
struct unsigned_tag {};
struct signed_tag {};
//! A numeric cast helper which handles the an unsigned source type
//! without generating compiler warnings.
template <typename Target, typename Source>
inline Target numeric_cast_helper( Source arg, unsigned_tag )
{
// An overflow condition.
if ( static_cast<typename promote_max_traits<Source, Target>::result>( arg ) >
static_cast<typename promote_max_traits<Source, Target>::result>( std::numeric_limits<Target>::max() ) ) {
throw numeric_cast_overflow();
}
return static_cast<Target>(arg);
}
//! A numeric cast helper which handles the an signed source type.
template <typename Target, typename Source>
inline Target numeric_cast_helper( Source arg, signed_tag )
{
// A loss of negative range, or more generally an underflow.
if ( ( arg < 0 && !std::numeric_limits<Target>::is_signed ) ||
( static_cast<typename promote_min_traits<Source, Target>::result>( arg ) <
static_cast<typename promote_min_traits<Source, Target>::result>( std::numeric_limits<Target>::min() ) ) ) {
throw numeric_cast_underflow();
}
// A loss of positive range.
if ( static_cast<typename promote_max_traits<Source, Target>::result>( arg ) >
static_cast<typename promote_max_traits<Source, Target>::result>( std::numeric_limits<Target>::max() ) ) {
throw numeric_cast_overflow();
}
return static_cast<Target>(arg);
}
} // end of namespace internal
//! A numeric cast which throws on overflow or underflow.
template <typename Target, typename Source>
inline Target numeric_cast( Source arg )
{
typedef typename uiro::type::ct_if<std::numeric_limits<Source>::is_signed, typename internal::signed_tag, typename internal::unsigned_tag>::result tag;
return internal::numeric_cast_helper<Target>( arg, tag() );
}
} // end of namespace uiro
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk