Boost logo

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