定义良好的位偏移超过32位,没有编译器警告
Well-defined bit-shifting more than 32 bits w/o compiler warning
这是一个愚蠢的问题,部分原因是为了好玩。
我有一个"定义明确"(或"饱和"?(的位掩码函数
template <unsigned N>
uint32_t mask(uint32_t x) {
const uint32_t MASK = N >= 32 ? ~uint32_t(0) : (uint32_t(1) << N) - 1;
return x & MASK;
}
预期行为:
uint32_t x = ~uint32_t(0); // 0xFFFFFFFF
mask<8>(x) => 0x000000FF
mask<24>(x) => 0x00FFFFFF
mask<32>(x) => 0xFFFFFFFF
mask<1234>(x) => 0xFFFFFFFF
但我不喜欢在mask<1234>()
中有一个未定义的代码uint32_t(1) << 1234
,尽管它是100%无害的(不应该评估它(。我不想看到编译器警告。
为什么不';t左位移位<lt&";,对于32位整数,当使用超过32次时,是否能按预期工作请参阅下面的更新
请给我一些小技巧(和模板元编程?(来摆脱uint32_t(1) << 1234
。
我有GCC 4.9,它(部分(支持C++14,并且足够聪明,可以进行恒定折叠等
更新
引用自C++14规范的N4140草案:
5.8轮班操作员【经验轮班】
如果右操作数为负数,或大于或等于提升后的左操作数的位长度。
你们有没有非模板的解决方案?
您可能会使用部分专业化(如果警告困扰您(,灵感来自boost enable_if
:
template <bool, unsigned N>
struct umask32 {
static const uint32_t val = (uint32_t(1) << N) - 1;
};
template <unsigned N>
struct umask32<true, N> {
static const uint32_t val = ~uint32_t(0);
};
template <unsigned N>
uint32_t mask(uint32_t x) {
const uint32_t MASK = umask32<(N >= 32), N>::val;
return x & MASK;
}
如果是N>=32
,则将使用第二个umask32
结构,否则将使用第一个结构,从而避免移位>=32
位的代码。
您可以为允许N
定义一个版本,为不允许的版本定义另一个版本:
using my_unsigned = unsigned;
template <my_unsigned N, typename std::enable_if<(N < 8 * sizeof(my_unsigned))>::type* = nullptr >
uint32_t mask(uint32_t x) {
const uint32_t MASK = (uint32_t(1) << N) - 1;
return x & MASK;
}
template <my_unsigned N, typename std::enable_if<(N >= 8 * sizeof(my_unsigned))>::type* = nullptr >
uint32_t mask(uint32_t x) {
return x;
}
由于SFINAE,当N < 2^sizeof(unsigned)
时,第一个版本将被实例化,否则编译器将选择(愚蠢的(第二个版本。
相关文章:
- 将应用程序从32位移植到64位时出现问题
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- qmake:检测目标位宽(32 位或 64 位)
- 如何在 64 位 vb.net Windows 应用程序中引用 32 位 dll
- 浮点数为 32 位和 64 位二进制表示形式
- C++易失性:保证 32 位访问?
- C++将 16 位值转换为 32 位值
- 如何在 64 位平台上计算 32 位哈希C++?
- C++中的24位到32位转换
- 在机器字大小等于 32 位的计算机上int64_t如何工作?
- uint32_t如何保证 32 位?
- 将代码从 32 位迁移到 64 位时出现问题 Visual Studio 2010
- 如何将32位字符与内联assembelyc++中的32位字符进行比较
- 一个32位版本的应用程序,建立在CentOS 6 x64上,当在较新的Linux上启动时,在"dl_itera
- x86 32位对Cuda的支持
- 我把我的编译器从32位转换为64位,但我仍然不能使用超过2GB:(为什么
- 定义良好的位偏移超过32位,没有编译器警告
- 当从64位转换为32位时,Gcc不会给出任何警告
- 32 位 64 位 - 警告:右移计数 >= 32 位计算机上的类型宽度
- 使用for循环对32位和64位容器/字符串的元素进行反向迭代而不发出警告