Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does undefined behavior affect static_assert?

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?

like image 939
Ruslan Avatar asked Mar 06 '19 19:03

Ruslan


2 Answers

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; /*...*/; /*...*/)
{
    /*...*/
}
like image 44
Kit. Avatar answered Oct 12 '22 23:10

Kit.


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); /*...*/; /*...*/)
{
    /*...*/
}
like image 124
R Sahu Avatar answered Oct 12 '22 23:10

R Sahu