From 0e29675ef55374b78690d804378f5e4c40cd72b4 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 29 Jun 2016 17:53:44 +1000 Subject: [PATCH] cast: tighten trunc_cast type restrictions trunc_cast should be between float/int/uint or to types of lesser precision. also restrict to fundamental types until we actually test with arbitrary types. --- cast.hpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/cast.hpp b/cast.hpp index 3868a94b..f03cc930 100644 --- a/cast.hpp +++ b/cast.hpp @@ -71,26 +71,36 @@ sign_cast (const U u) /// assert if the value cannot be cast loslessly from U to T, else return the /// converted value.Note: this is only a debug-time check and is compiled out /// in optimised builds. +/// +/// relies on equality operators being present and behaving sanely. attempts +/// to preserve NaN values. +/// +/// allows the identity cast (if only to make cross-platform porting easier) template < typename T, typename U > std::enable_if_t< - // either we're casting from real to integer - !std::is_floating_point::value && std::is_floating_point::value - // or we're reducing the size of the type - || sizeof (T) < sizeof (U), + // only enabled for builtin types. there's no reason this couldn't be + // extended, but we've only really tested on integers and floats. + std::is_fundamental::value && std::is_fundamental::value && ( + // either we're casting between real and integer + std::is_floating_point::value != std::is_floating_point::value + // or we're reducing the size of the type + || sizeof (T) <= sizeof (U) + ), T > -trunc_cast (U u) +trunc_cast (const U &u) { auto t = static_cast (u); - // assume testing round-trip error is the same as half-trip error. this - // makes satisfying the type system (for the debug checks) a lot easier, - // but seems like it might bite us later... + // if we're not a NaN then check equality by casting U-to-T-to-U. we can't + // explicitly check isnan because that call isn't valid for arbitrary + // types and we'll cause a compile-time error. if (u == u) CHECK_EQ (static_cast (t), u); + // we must be a NaN. test that t is a NaN too by self-equality. else CHECK_NEQ (t, t);