Consider the following code:
SomeType x=getX();
for(auto mask = 1u<<(CHAR_BIT*sizeof x - 1);/*...*/;/*...*/)
{
static_assert(sizeof mask>=sizeof x, "Type of numeric parameter is too long");
/*...*/
}
Here, mask
will have type unsigned
. Suppose SomeType
is long long
. Then the initialization of mask
will have undefined behavior due to shifting by too much. But OTOH, there's a static_assert
, which checks that undefined behavior can't happen at runtime (because the code would fail to compile).
But since UB can lead to time paradoxes and other surprises, I'm not so sure that static_assert
is guaranteed to actually work in this case. Is there any reason to be sure of this? Or should this code be redone to make static_assert
appear before initialization of mask
?
If SomeType
is an integral type and you are using C++11 or newer, you might be able to eliminate the assert altogether by using:
auto one = std::make_unsigned<SomeType>::type(1);
for(auto mask = one << CHAR_BIT*sizeof x-1; /*...*/; /*...*/)
{
/*...*/
}
Since you know you are going to use unsigned
as the type for mask
, there is no need to rely on mask
to do the static_assert
. Do it right after before the loop begins.
SomeType x = getX();
static_assert(sizeof 1u >= sizeof x, "Type of numeric parameter is too long");
for(auto mask = 1u << CHAR_BIT*sizeof x-1; /*...*/; /*...*/)
{
/*...*/
}
A cleaner option would be to use a helper function.
template <typename RetType, typename SomeType>
RetType make_mask(RetType in, SomeType const& x)
{
static_assert(sizeof in >= sizeof SomeType, "Type of numeric parameter is too long");
return (in << (CHAR_BIT*sizeof SomeType)-1);
}
and use
for(auto mask = make_mask(1u, x); /*...*/; /*...*/)
{
/*...*/
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With