Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Boost or the Standard Library provide a way to check whether a cast is lossless?

Tags:

c++

boost

I am looking for a Standard Library or Boost function that can losslessly cast a number to another primitive type and somehow inform me whether the cast was lossless (or throw an exception if it is not). Here are some examples:

auto x = lossless_cast<double>(1u); // ok, double can represent 1
auto x = lossless_cast<int>(1.2); // fail, int can't represent 1.2
auto x = lossless_cast<int>(1E200); // fail, int can't represent 1E200

boost::numeric_cast comes close in that it will pick up casts that fall out of the numeric range of the target type, but not if they are lossless but within the target type (see my 2nd example).

There is a SO question for the C language which provides some hand-rolled solutions to this problem, but I am after a boost or Standard Library solution, basically with the following functionality:

template <typename out, typename in>
out lossless_cast(in in_value)
{
  out out_value = static_cast<out>(in_value);

  if (static_cast<in>(out_value) != in_value)
    throw; // some exception

  return out_value;
}

Does this functionality exist?

like image 710
quant Avatar asked May 11 '15 01:05

quant


1 Answers

I'm pretty sure there's nothing pre-rolled in the Standard, and not aware of anything in boost but it's a big library. Any implementation using casting has to be careful of the undefined behaviour for out-of-range values per 4.9 [conv.fpint], but as boost::numeric_cast<> ostensibly handles that, you could use:

template <typename U, typename T>
inline U is_lossless(T t)
{
    U u = boost::numeric_cast<U>(t);
    T t2 = boost::numeric_cast<T>(u); // throw if now out-of-range
    if (t != t2)
        throw whatever-you-like;
    return u;
}

The need for numeric_cast<> when recovering t2 is least obvious: it ensures that u is still in range, as it's possible for a value cast from say int64_t x to double y to succeed but be approximated with an integral value in y than's out of range for an int64_t, such that casting back from double has undefined behaviour.

The legality/robustness of the above requires that boost::numeric_cast<> correctly avoids undefined behaviour, which I haven't verified.

like image 117
Tony Delroy Avatar answered Nov 18 '22 19:11

Tony Delroy