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).