# 如何检查整数中是否只设置了一位？

I want to write a function `HasOneBit`, that

• accepts any integer type (signed or unsigned, 8 to 64 bits),
• is `constexpr`,
• does not invoke undefined behaviour.

``````bool HasOneBit (std::uint64_t value)
{
return value != 0 && (value & (value - 1)) == 0;
}
``````

This underflows, if type of `value` would be a signed integer, and we passed the smallest value to the function. Do I have to overload the function 8 times to implement all possibilities?

• 芦苇F浅 回复

The following template function satisfies all criteria (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;
}
``````

This won't invoke undefined behaviour, because `value` is first converted to the unsigned counterpart of `T`. This conversion does not change the bit representation of `value`.

I think, the relevant quote from the standard is this (see N4713, [conv.integral]#2):

如果目标类型是无符号的，则结果值是与源整数一致的最小无符号整数（模2n，其中n是用于表示无符号类型的位数）。 [注：在二进制补码表示中，此转换是概念性的，并且位模式没有任何变化（如果没有截断）。 —尾注]

A newer version of this rule is even simpler. Not sure, whether this applies to the unsigned to signed conversion as well.

否则，结果是目标类型的唯一值，该唯一值与源整数模2N一致，其中N是目标类型的宽度。