std::has_single_bit 是 c++20 引入的 constexpr 函数,用于判断整数是否为 2 的非负整数次幂(即二进制中仅一位为 1 且不为 0),仅接受无符号整型,对 0 返回 false,负数输入导致未定义行为。

std::has_single_bit 是什么,它能检查什么
std::has_single_bit 是 C++20 引入的 constexpr 工具函数,用于判断一个整数是否恰好只有一个二进制位为 1(即该数是 2 的非负整数次幂:1, 2, 4, 8, 16…),且不为 0。它不关心具体哪一位,只回答“是不是仅有一位被置位”。
常见误用是以为它能返回位置索引(比如第几位是 1)或支持负数——它不支持。传入 0 返回 false;传入负数会触发未定义行为(因为参数类型是无符号整型或可隐式转换为无符号整型的整型,实际使用中若传 int 负值会被重解释为大正数,结果不可靠)。
- 只接受整型类型(
unsigned int、std::size_t、long long等),不接受浮点或指针 - 对
1返回true(0b1),对3(0b11)返回false - 底层通常编译为单条
bt+jc或popcnt指令,在 x86-64 上确实是“极速”
怎么用:基本调用与类型适配
直接传入变量或字面量即可,但要注意类型匹配和符号问题:
if (std::has_single_bit(static_cast<unsigned int>(x))) { /* ... */ }</unsigned>
如果 x 是有符号类型(如 int),必须显式转为无符号类型,否则可能因符号扩展或负值导致意外结果。编译器不会报错,但行为未定义。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 推荐统一用
std::make_unsigned_t<decltype></decltype>转换,比硬写unsigned int更安全 - 对
size_t、uintptr_t等平台相关类型,直接传入即可(它们本就是无符号) - 不能用于
bool(虽可隐式转成int,但语义不符;std::has_single_bit(true)等价于std::has_single_bit(1),纯属巧合)
和 hand-written 检查对比:为什么别自己写 (x & (x-1)) == 0
手动写 (x & (x - 1)) == 0 看似等价,但有关键差异:
- 它对
x == 0也返回true(因为0 & 0xffffffff == 0),而std::has_single_bit(0)明确返回false - 它对负数
x在有符号算术下行为依赖补码实现,不可移植;std::has_single_bit要求无符号输入,边界更清晰 - 现代编译器(GCC 12+、Clang 14+)对
std::has_single_bit生成的汇编通常更紧凑,且能更好参与常量折叠 - 它明确表达意图:不是“清最低位后为零”,而是“是否恰好一个位为 1”——语义更直白,可读性更强
容易忽略的陷阱:constexpr 限制与模板推导
std::has_single_bit 是 constexpr 函数,但它的参数必须是常量表达式才能在编译期求值。运行时变量调用没问题,但想用在 static_assert 或模板非类型参数里,就得确保输入是字面量或 constexpr 变量。
- 错误示例:
static_assert(std::has_single_bit(n));—— 若n不是constexpr,编译失败 - 模板推导时,比如
template<auto v> struct S { static constexpr bool v = std::has_single_bit(V); };</auto>,V必须是字面量常量(如S合法,S<x></x>非法) - 对
std::uint8_t这类窄类型,传入时会被提升,但函数内部仍按无符号整型处理,结果正确;不过若你依赖精确位宽语义(比如只允许 8 位内有效),需额外校验范围
真正需要“极速”的场景,往往是位图索引、内存对齐验证或哈希表容量预判——这时候少一次分支、多一分确定性,就藏在这些细节里。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










