Reputation: 862
I have an annoying compiler warning in my C++ project. It is in a templated function, which checks wether its argument can fit into the range of a particular type, which is mentioned as a template parameter (couldn't find it in standart library, does it have one?).
I am aware of tricky signed to unsigned integral types comparison, thus I specialized this function for differently signed integers, where I firstly check if signed integer is non-negative right before signed to unsiged comparison. However gcc issues a warning for this safe case. I don't want to disable this warning with -Wsign-compare totally, because it is a useful one. The code is listed bellow:
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();
// ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upvotes: 3
Views: 1595
Reputation: 2937
There are a few options:
1 UINT_MAX
isInRangeOf<unsigned int>( std::numeric_limits<unsigned_int>::max() );
isInRangeOf<unsigned int>( UINT_MAX );
// GCC specific
isInRangeOf<unsigned int>( __UINT32_MAX__ );
2 Bitwise tricks
isInRangeOf<unsigned int>( static_cast<unsigned int>(-1) )
isInRangeOf<unsigned int>( ~0 )
isInRangeOf<unsigned int>( 0xFFFFFFFF )
3 Suppress warnings by pragma directives
(this option can be useful for some unused parameters warnings, when doing some template meta-programming)
#ifdef __GNUG__
# define PUSH_IGNORE_WSIGN_CMP\
_Pragma("GCC diagnostic push")\
_Pragma("GCC diagnostic ignored \"-Wsign-compare\" ")
# define POP_IGNORE_WSIGN_CMP _Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
# define PUSH_IGNORE_WSIGN_CMP
_Pragma("warning( push )")\
_Pragma("warning( disable : C4018)")
# define POP_IGNORE_WSIGN_CMP _Pragma("warning( pop )")
#endif
PUSH_IGNORE_WSIGN_CMP
if (!isInRangeOf<unsigned int>(-1)){
POP_IGNORE_WSIGN_CMP
std::cout << "false";
Upvotes: 3
Reputation: 16016
Before the code:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
After the code:
#pragma GCC diagnostic pop
If you want to expand this from a macro to support non-GCC compilers, then use the equivalent _Pragma()
form
Edge cases:
In old versions of GCC (4.6? docs don't say), this had to be around the function, but now it can be done at any scope.
There may be problems if you try to suppress a warning in a macro, then trigger it in the same macro.
Some compiler versions may fail to suppress associated note:
s for some diagnostics.
Upvotes: 5
Reputation: 171097
Once you've verified suspect
is nonnegative, you can safely cast it to its type's unsigned version:
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();
}
Upvotes: 5