我有一个对通用类型的值执行否定检查的函数(我不想假设该类型,它不一定是模板化的)。但是,启用-Wtype-limits
时,编译器会抱怨有关类型是否为无符号类型的否定检查。如果类型可能更改为带符号的类型,则删除否定检查是一个坏主意,并且禁用警告也不是理想的选择,因为它可能会引起合法问题。
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 ...
}
即使我使用C ++ 17并使用if constexpr(std::is_unsigned<example_t>::value)
来保护警告的检查,它仍然会发出警告。我注意到,如果GCC会触发警告,则不会为if constexpr
输出的代码发出警告,因为分配给这些类型的变量的值将超出该类型的范围。另外,即使我先将其强制转换为signed int
,GCC也会发出警告。警告行为与其自身不一致,因此这似乎是一个错误。 Clang对这些类型的检查完全不发出警告。
但是我想知道是否有办法解决,我的代码库严格符合C ++ 14,并且我们仍然使用旧的GCC编译器。
我不确定是否值得在可读性上产生影响,但是您可以使用通用lambda将比较移到模板上下文中。 GCC不会在模板代码中对此发出警告:
if ([](auto v){return v < 0;}(value) || value >= 9)
或者也许更好地编写一个函数:
template<typename T>
constexpr bool is_negative(T t) { return t < 0; }
并使用它:
if (is_negative(value) || value >= 9)
或仅使用std::less
也不会警告:
if (std::less()(value, 0) || value >= 9)
GCC还具有#pragma
来暂时禁用警告,请参阅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