我的C++项目中有一个讨厌的编译器警告.它是一个模板化的函数,它检查它的参数是否适合特定类型的范围,它被提到作为模板参数(在标准库中找不到它,它有一个?).
我知道有问题的签名到无符号整数类型比较,因此我将这个函数专门用于不同的有符号整数,我首先检查有符号整数是否在签署到未进行比较之前是非负的.但是,gcc会对此安全案例发出警告.我不想完全禁用-Wsign-compare来禁用此警告,因为它是一个有用的警告.代码列在下面:
template <typename TRange, typename TSuspect, typename TCommonSignedness>
bool isInRangeOfHelper(const TSuspect & suspect,
const TCommonSignedness &,
const TCommonSignedness &)
{
return std::numeric_limits<TRange>::min() <= suspect
&& suspect <= std::numeric_limits<TRange>::max();
}
template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect,
const std::true_type &,
const std::false_type &)
{
return suspect <= std::numeric_limits<TRange>::max();
}
template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect,
const std::false_type &,
const std::true_type &)
{
return 0 <= suspect
&& suspect <= std::numeric_limits<TRange>::max(); // WARNING HERE
}
template <typename TRange, typename TSuspect>
bool isInRangeOf(const TSuspect & suspect){
return isInRangeOfHelper<TRange>(suspect,
std::is_signed<TRange>(),
std::is_signed<TSuspect>());
}
template <typename TRange>
bool isInRangeOf(const TRange & suspect){ return true; }
int main(int argc, char *argv[]){
if (!isInRangeOf<unsigned int>(-1)){
std::cout << "false";
} else {
std::cout << "predicate error";
std::terminate();
}
return 0;
}
// warning: comparison of integer expressions of different signedness:
// ‘const int’ and ‘unsigned int’ [-Wsign-compare]
// return 0 <= suspect && suspect <= std::numeric_limits<TRange>::max();
// ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
一旦您验证了suspect非负,您可以安全地将其强制转换为其类型的无符号版本:
template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect,
const std::false_type &,
const std::true_type &)
{
return 0 <= suspect
&& static_cast<std::make_unsigned_t<TSuspect>>(suspect) <= std::numeric_limits<TRange>::max();
}
Run Code Online (Sandbox Code Playgroud)
之前的代码:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
Run Code Online (Sandbox Code Playgroud)
代码后:
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)
如果要从宏扩展此_Pragma()格式以支持非GCC编译器,请使用等效形式
边缘情况:
在旧版本的GCC中(4.6吗?文档未说),这必须围绕该函数进行,但是现在可以在任何范围内完成。
如果您尝试在宏中禁止显示警告,然后在同一宏中触发它,则可能会出现问题。
note:对于某些诊断,某些编译器版本可能无法抑制关联的。