std::has_single_bit 是 c++20 引入的 constexpr 函数,用于判断无符号整数是否为 2 的正整数次幂(即二进制中仅一个位为 1),对 0 和负数返回 false,且要求参数为无符号类型以避免未定义行为。

std::has_single_bit 是什么,它能检查什么
std::has_single_bit 是 C++20 引入的 constexpr 工具函数,用于判断一个整数是否恰好只有一个二进制位被置为 1(即该数是 2 的非负整数次幂:1, 2, 4, 8, 16…),且要求输入为无符号整型或可隐式转换为无符号整型的整型类型。
它不检查“是否为 2 的幂”这种数学定义下的全部情况——例如 0 和负数会直接返回 false,且对有符号类型(如 int)传入负值时行为未定义(实际编译器通常按位模式解释,但不可靠)。
常见误用:拿它检查 0 或 -4,结果不可靠;或误以为它等价于 (x & (x - 1)) == 0(后者对 x == 0 返回 true,而 std::has_single_bit(0) 明确返回 false)。
怎么安全调用 std::has_single_bit
必须确保参数是无符号类型,或显式转换为无符号类型后再传入。标准库只对 unsigned char、unsigned short、unsigned int、unsigned long、unsigned long long 及其扩展(如 std::size_t)提供特化。
- ✅ 正确写法:
std::has_single_bit(static_cast<unsigned int>(x))</unsigned> - ✅ 安全泛化(C++20 起):
std::has_single_bit(static_cast<:make_unsigned_t>>(x))</:make_unsigned_t> - ❌ 危险写法:
std::has_single_bit(-4)(未定义行为) - ❌ 错误假设:
std::has_single_bit(0)返回 true(实际返回 false)
和手写位运算比,快在哪?为什么叫“极速”
名字里的“极速”不是营销话术——它在多数现代编译器(GCC 12+、Clang 14+、MSVC 19.30+)下会被直接编译为单条 CPU 指令,比如 x86-64 的 tzcnt + cmp,或 ARM64 的 clz + 条件判断,无需分支预测,也不依赖循环或查表。
而传统写法 (x != 0) && ((x & (x - 1)) == 0) 至少需要 3~4 条指令,且含条件跳转,在某些流水线场景下可能更慢。
注意点:
- 仅当启用 BMI1 指令集(GCC/Clang 加
-mbmi,MSVC 默认开启)时,tzcnt才真正高效;否则回落为等效软件逻辑 - 对常量表达式,所有主流编译器都能在编译期完全求值,生成
true或false字面量 - 它不处理浮点数、指针或自定义类型——试图传入会编译失败
实际使用中容易被忽略的边界
最常被跳过的三点:
-
std::has_single_bit(1)返回true(2⁰),但很多人误以为“单个 bit”必须是高位,其实最低位也算 - 对
std::size_t在 64 位平台为unsigned long long,传入1ULL 是合法且返回 true;但 <code>1ULL 是未定义行为(左移超位宽),<code>std::has_single_bit不做越界检查 - 它不区分“是否为 2 的幂”和“是否为正 2 的幂”——
std::has_single_bit的语义就是“是否为正的、2 的整数次幂”,1合法,0和负数非法
如果你的逻辑本意是“非零且是 2 的幂”,那就直接用 std::has_single_bit;如果需要兼容 0(比如表示“空集合”),就得单独判断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











