Kaleb Barrett
Kaleb Barrett

Reputation: 1594

Using -Wtype-limits with type generic code

I have a function that performs a negative check on a value of a generic type (well I don't want to assume the type, it is not necessarily templated). However, with -Wtype-limits enabled, the compiler complains about the negative check if the type in question is an unsigned type. Removing the negative check is a bad idea if the type might change to be a signed type, and disabling the warnings is not ideal, as it might catch legitimate issues.

using example_t = uint8_t;   // could be int8_t or int64_t or really whatever integer type that can store values 0 - 8.

void example(example_t value) {
    if (value < 0 || value >= 9) {  // <-- errors on the 'value < 0' check
        throw std::invalid_argument("some error message");
    }
    // continue processing ...
}

Even if I use C++17 and use if constexpr(std::is_unsigned<example_t>::value) to guard the check that is warning, it still warns. I've noticed that GCC does not emit warning for if constexpr'd out code if it would trigger warnings because the value assigned into variables of those type would fall out of the range of the type. Also, GCC emits the warning even if I cast it to a signed int first. The warning behavior is not consistent with itself, so this seems like a bug. Clang issues no warning at all for these types of checks.

But I wondering if there was a way around this, my code base is strictly C++14 compliant, and we are stuck with old GCC compilers.

Upvotes: 2

Views: 389

Answers (1)

walnut
walnut

Reputation: 22152

I am not sure it is worth the impact on readability, but you can move the comparison into a template context using a generic lambda. GCC doesn't warn about this in the templated code:

if ([](auto v){return v < 0;}(value) || value >= 9)

or maybe better write a function:

template<typename T>
constexpr bool is_negative(T t) { return t < 0; }

and use that:

if (is_negative(value) || value >= 9)

or just using std::less also wont warn:

if (std::less()(value, 0) || value >= 9)

GCC also has #pragmas to disable warnings temporarily, see this question:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
if (value < 0 || value >= 9) {
    throw std::invalid_argument("some error message");
}
#pragma GCC diagnostic pop

Upvotes: 2

Related Questions