c++typestype-traitssignednegative-zero

Is it possible to test whether a type supports negative zero in C++ at compile time?


Is there a way to write a type trait to determine whether a type supports negative zero in C++ (including integer representations such as sign-and-magnitude)? I don't see anything that directly does that, and std::signbit doesn't appear to be constexpr.

To clarify: I'm asking because I want to know whether this is possible, regardless of what the use case might be, if any.


Solution

  • The best one can do is to rule out the possibility of signed zero at compile time, but never be completely positive about its existence at compile time. The C++ standard goes a long way to prevent checking binary representation at compile time:

    The only thing one can test is if the domain of an integer type is dense enough to rule-out signed zero:

    template<typename T>
    constexpr bool test_possible_signed_zero()
    {
        using limits = std::numeric_limits<T>;
        if constexpr (std::is_fundamental_v<T> &&
               limits::is_exact &&
               limits::is_integer) {
            auto low = limits::min();
            auto high = limits::max();
            T carry = 1;
            // This is one of the simplest ways to check that
            // the max() - min() + 1 == 2 ** bits
            // without stepping out into undefined behavior.
            for (auto bits = limits::digits ; bits > 0 ; --bits) {
                auto adder = low % 2 + high %2 + carry;
                if (adder % 2 != 0) return true;
                carry = adder / 2;
                low /= 2;
                high /= 2;
            }
            return false;
        } else {
            return true;
        }
    }
    
    template <typename T>
    class is_possible_signed_zero:
     public std::integral_constant<bool, test_possible_signed_zero<T>()>
    {};
    template <typename T>
    constexpr bool is_possible_signed_zero_v = is_possible_signed_zero<T>::value;
    

    It is only guaranteed that if this trait returns false then no signed zero is possible. This assurance is very weak, but I can't see any stronger assurance. Also, it says nothing constructive about floating point types. I could not find any reasonable way to test floating point types.