未定义的行为会影响static_assert吗?

时间:2019-03-06 19:52:50

标签: c++ undefined-behavior static-assert

考虑以下代码:

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。假设SomeTypelong long。然后,mask的初始化由于移位过多而将具有不确定的行为。但是OTOH中有一个static_assert,它检查运行时不会发生未定义的行为(因为代码无法编译)。

但是,由于UB可能导致时间悖论和其他意外情况,因此我不确定static_assert在这种情况下是否可以正常工作。有什么理由可以确定吗?还是应该重做此代码以使static_assert初始化之前出现mask

2 个答案:

答案 0 :(得分:2)

由于您知道将使用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); /*...*/; /*...*/)
{
    /*...*/
}

答案 1 :(得分:1)

如果SomeType是整数类型,并且您使用的是C ++ 11或更高版本,则可以使用以下方法完全消除断言:

auto one = std::make_unsigned<SomeType>::type(1);
for(auto mask = one << CHAR_BIT*sizeof x-1; /*...*/; /*...*/)
{
    /*...*/
}