C++17下如何让MSVC的__popcnt64支持在constexpr函数中使用
C++17 MSVC环境constexpr 64位位计数适配方案
MSVC提供的__popcnt64内置函数在C++17标准下不支持constexpr调用,无法直接替换GCC的__builtin_popcountll实现编译期位计数需求,可通过以下两种方案解决:
方案1:纯标准C++17实现(推荐)
手写无编译器依赖的constexpr位计数逻辑,开启O2优化后MSVC会自动将该逻辑编译为原生popcnt指令,运行性能和内置函数完全一致。
首先实现通用constexpr位计数函数:
#include <cstdint> constexpr int popcountll(uint64_t mask) noexcept { mask = mask - ((mask >> 1) & 0x5555555555555555); mask = (mask & 0x3333333333333333) + ((mask >> 2) & 0x3333333333333333); mask = (mask + (mask >> 4)) & 0x0F0F0F0F0F0F0F0F; return static_cast<int>((mask * 0x0101010101010101) >> 56); }
修改你的成员函数即可正常使用:
[[nodiscard]] constexpr int count() const noexcept { // 如果mask是有符号int64_t,需改为return popcountll(static_cast<uint64_t>(mask)); return popcountll(mask); }
方案2:跨编译器兼容实现
如果需要同时兼容GCC和MSVC环境,可通过预编译宏区分编译器,GCC继续用原生内置函数,MSVC用自定义实现:
#include <cstdint> #ifdef __GNUC__ constexpr int popcountll(uint64_t mask) noexcept { return __builtin_popcountll(mask); } #else constexpr int popcountll(uint64_t mask) noexcept { mask = mask - ((mask >> 1) & 0x5555555555555555); mask = (mask & 0x3333333333333333) + ((mask >> 2) & 0x3333333333333333); mask = (mask + (mask >> 4)) & 0x0F0F0F0F0F0F0F0F; return static_cast<int>((mask * 0x0101010101010101) >> 56); } #endif
成员函数调用方式和方案1完全一致。
注意事项
- 请确保传入位计数函数的参数为无符号64位类型
uint64_t,若原成员变量mask为有符号int64_t,调用前需要做无符号转换,避免右移操作出现符号位扩展导致计算错误。
内容的提问来源于stack exchange,提问作者QuarterlyQuotaOfQuotes
相关产品推荐
相关产品推荐

