std::popcount 是 C++20 引入的用于计算无符号整数二进制中 1 的个数的 constexpr 函数,仅接受无符号类型,需对有符号数用 static_cast 保持位模式不变。

std::popcount 是什么,为什么不能直接用
std::popcount 是 C++20 引入的 头文件中的函数,用于计算无符号整数二进制表示中 1 的个数(即汉明重量)。但它**仅接受无符号类型**,传入 int、long 等有符号类型会编译失败——这不是 bug,是标准明确要求的重载限制。
- 合法调用:
std::popcount(static_cast、(x)) std::popcount(uint64_t{val}) - 非法调用:
std::popcount(-1)、std::popcount(42)(若 42 是int类型) - 底层依赖硬件指令(如 x86 的
popcnt),比手写循环或查表更快更可靠
如何安全传入有符号整数
多数场景下变量是 int 或 long,需显式转换。关键不是“转成 unsigned”,而是**保持位模式不变**——对补码系统,这等价于 reinterpret cast,但标准推荐用 static_cast 配合无符号对应类型。
- 对
int:用static_cast(不推荐unsigned,因大小不保) - 对
long long:必须用static_cast,否则可能截断 - 对负数:
std::popcount(static_cast(在 32 位(-1)) == 32 int平台),这是预期行为
int x = -5; // 二进制补码:...11111011 auto count = std::popcount(static_cast(x)); // 正确:统计所有位中的 1
编译器支持与替代方案
Clang 11+、GCC 9.1+、MSVC 19.28+ 支持 std::popcount;但若项目需兼容 C++17 或更早,不能直接降级使用。此时不要手写朴素循环(O(N)),优先考虑:
-
__builtin_popcount(GCC/Clang):对unsigned int;__builtin_popcountll对unsigned long long -
_mm_popcnt_u32(MSVC +),需启用/arch:AVX2或类似选项 - 避免用
std::bitset做运行时值统计——它只接受编译期常量 N,且构造开销大::count()
常见误用和性能陷阱
最典型的错误是忽略类型匹配,导致编译失败或静默调用错误重载(如误触发模板版本而没定义)。另一个容易被忽略的点是:std::popcount 不处理浮点数或指针,也不能用于数组或自定义类型。
立即学习“C++免费学习笔记(深入)”;
- 错误示例:
std::popcount(0x123)—— 字面量类型是int,非 unsigned,GCC 报错no matching function - 正确写法:
std::popcount(0x123u)、std::popcount(0x123ULL) - 对齐无关:该函数不关心内存布局,只作用于值本身,无需担心结构体字段偏移
- constexpr 友好:只要输入是字面量或 constexpr 变量,结果也是 constexpr
constexpr auto c = std::popcount(0b1010u); // c == 2,编译期求值C++20 的
std::popcount 看似简单,但类型系统卡得严,实际用时几乎每次都要加 static_cast。别图省事写宏封装,容易掩盖有符号扩展问题;老老实实按类型配对,才是稳定之道。











