c++castingc++98range-checking

What is a safe, cross-platform way to perform range checks before casting to a smaller numeric type?


Here is the closest duplicate I could find.

Despite the tags, the question seems to be about C, and the usable answer references the C99 spec.

What is the correct way to handle this check in C++98, without using Boost or other libraries?


Solution

  • You can copy the code from gsl::narrow() and tweak it slightly, turning it into can_narrow() returning a bool rather than throwing:

    // narrow_cast(): a searchable way to do narrowing casts of values
    template<class T, class U>
    inline constexpr T narrow_cast(U u) noexcept
    { return static_cast<T>(u); }
    
    namespace details
    {
        template<class T, class U>
        struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
        {};
    }
    
    template<class T, class U>
    inline bool can_narrow(U u)
    {
        T t = narrow_cast<T>(u);
        if (static_cast<U>(t) != u)
            return false;
        if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
            return false;
        return true;
    }