【问题标题】:How to check whether exactly one bit is set in an integer?如何检查整数中是否恰好设置了一位?
【发布时间】:2020-04-24 15:32:32
【问题描述】:
我想写一个函数HasOneBit,那个
- 接受任何整数类型(有符号或无符号,8 到 64 位),
- 是
constexpr,
- 不调用未定义的行为。
我试图概括这一点:
bool HasOneBit (std::uint64_t value)
{
return value != 0 && (value & (value - 1)) == 0;
}
如果value 的类型是有符号整数,则会下溢,并且我们将最小值传递给函数。我是否必须重载函数 8 次才能实现所有可能性?
【问题讨论】:
标签:
c++
type-conversion
integer
【解决方案1】:
以下模板函数满足所有条件 (live demo):
template <class T>
constexpr bool HasOneBit (T value)
{
static_assert (std::is_integral<T>::value && !std::is_same<T, bool>::value,
"This function should be used only with integers.");
const std::make_unsigned_t<T> unsignedValue = value;
return unsignedValue != 0 && (unsignedValue & (unsignedValue - 1)) == 0;
}
这不会调用未定义的行为,因为value 首先转换为T 的未签名对应项。此转换不会更改value 的位表示。
我认为,标准中的相关引用是这样的(参见N4713,[conv.integral]#2):
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n 其中 n是用于表示无符号类型的位数)。 [注意: 在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 ——尾注]
newer version of this rule 更简单。不确定,这是否也适用于无符号到有符号的转换。
否则,结果是与源整数模2N一致的目标类型的唯一值,其中N为目标类型的宽度。