1

I wrote a short function to count the number of digits (integer portion) of a value.

template <typename T>
static size_t digits(T num) {
    auto is_fraction_of_one = [](T num) {
        return (num > 0 && num < 1) || (num > -1 && num < 0);
    };
    if (num == 0 || is_fraction_of_one(num))
        return 1;

    return std::is_unsigned_v<T> ? \
            static_cast<size_t>(std::log10(num)) + size_t(1) : \
            static_cast<size_t>(std::log10(num < 0 ? -num : num)) + size_t(1);
}

If 0 <= abs(num) < 1 it returns 1, otherwise it computes the number of digits via std::log10(num)+1.

The code works as-is, but the compiler (Windows VC++) warns:

warning C4146: unary minus operator applied to unsigned type, result still unsigned

which is fair, since it doesn't recognize that the -num part in the last line will only execute when T is signed.

If I wanted rewrite the code to prevent this warning, how could I do it?

Since std::is_unsigned_v is constexpr, I feel like I should be able to split the code into two separate template functions: one for when T is signed, and another for when it is not. But I can't figure out how to do it properly.


Note:

I realize I could shorten the code, and prevent the warning by casting num to a double (since std::log10 will do that anyway without a template arg):

template <typename T>
static size_t digits(T num) {
    double dnum = std::fabs(static_cast<double>(num));
    if (dnum >= 0.0 && dnum < 10.0)
        return 1;
    return static_cast<size_t>(std::log10(dnum)) + size_t(1);
}

but I'm asking the question primarily for my own education. Also, I do have some other functions which would more aptly benefit from the solution (whatever that may be).

coulomb
  • 698
  • 6
  • 16
  • 1
    I've added a new answer to the dupe target that shows how you could leverage `if constexpr` instead of specializing the template. – NathanOliver Oct 12 '18 at 20:41
  • @NathanOliver I can't comment to your answer (since I need 50 rep), nor can I upvote it (unfortunately), but it's perfect. I'm using c++17, and it keeps things very clean. Thanks for pointing me to it. – coulomb Oct 12 '18 at 21:25
  • Glad to hear it helped you out. Hopefully it will help others as well – NathanOliver Oct 12 '18 at 21:25
  • @NathanOliver Now I can upvote it! I'd better hurry before this question gets downvoted again, and I lose the opportunity:) – coulomb Oct 13 '18 at 06:21

0 Answers0