请考虑以下代码:
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");
/*...*/
}
在这里,mask
将有类型unsigned
。假设SomeType
是long long
。然后mask
的初始化将由于过多的移位而具有未定义的行为。但OTOH,有一个static_assert
,它检查未定义的行为不能在运行时发生(因为代码将无法编译)。
但由于UB可能导致时间悖论和其他意外,我不太确定static_assert
能保证在这种情况下实际工作。有什么理由可以肯定吗?或者是否应重做此代码以使static_assert
在mask
初始化之前出现?
因为你知道你将使用unsigned
作为mask
的类型,所以没有必要依靠mask
来做static_assert
。在循环开始之前立即执行。
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; /*...*/; /*...*/)
{
/*...*/
}
更清洁的选择是使用辅助函数。
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);
}
并使用
for(auto mask = make_mask(1u, x); /*...*/; /*...*/)
{
/*...*/
}
如果SomeType
是一个整数类型,并且您使用的是C ++ 11或更高版本,则可以通过使用以下方法完全消除断言:
auto one = std::make_unsigned<SomeType>::type(1);
for(auto mask = one << CHAR_BIT*sizeof x-1; /*...*/; /*...*/)
{
/*...*/
}