C++ 从枚举值中获取位移位
C++ Get Bit Shift from Enum Value
假设我有一个用于标记的枚举,即
enum Flags { Flag1 = 1 << 0, Flag2 = 1 << 1, Flag3 = 1 << 2 };
如果给我一个Flags
值,我想知道这个值的位移是多少。本质上,对于 Flag1
我想 return 0,对于 Flag2
我想 return 1,等等。除了使用带有 switch
语句的函数。
我想要这个是因为我有一个数据数组,函数的 return 值是这个数组的元素之一。 return 的哪个元素取决于传递给函数的标志。
我想要一种更简洁的方法来执行以下操作。 特别是如果我修改枚举,我不需要返回并修改此函数。
myobj* objects[3] = { obj1, obj2, obj3 };
myobj* GetObj(Flags FlagValue)
{
switch(FlagValue)
{
case Flag1:
return objects[0];
case Flag2:
return objects[1];
case Flag3:
return objects[2];
}
}
像这样的东西应该可以工作:
int iFlag = (int)FlagValue;
int ix = 0;
while (iFlag > 1) {
ix++;
iFlag = iFlag >> 1;
}
return objects[ix];
为了安全起见,添加对 FlagValue <= 0
或 FlagValue >= (sizeof(objects) / sizeof(objects[0]))
等非法输入的检查。
您需要的是一个计算枚举值中尾随零的函数。有很多方法可以做到这一点(参见 https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear),但大多数现代平台通常提供专门的 CPU 指令来完成这项工作。由于该语言没有相应的运算符,因此只能通过非标准的特定于编译器的方式访问该指令,例如 GCC 中的 __builtin_ctz
或 MSVC 中的 _BitScanReverse
。
但是,如果您专门使用编译时值,则更好的 C++ 解决方案将遵循
template <unsigned N> struct ctz {
static const unsigned value = ctz<N - 1>::value + 1;
};
template <> struct ctz<1> {
static const unsigned value = 0;
};
template <> struct ctz<0>; // Left undefined
...
cout << ctz<Flag2>::value << endl;
最简洁(也可能是正确)的方法是重新设计设计。 'flag' 并不是真正的标志 - 它是一个索引,因此根据索引进行编码。
enum Index { I1, I2, I3, INDEX_COUNT };
myobj* objects[INDEX_COUNT] = { obj1, obj2, obj3 };
myobj* GetObj(Index i)
{
assert(i < INDEX_COUNT);
return objects[i];
}
假设我有一个用于标记的枚举,即
enum Flags { Flag1 = 1 << 0, Flag2 = 1 << 1, Flag3 = 1 << 2 };
如果给我一个Flags
值,我想知道这个值的位移是多少。本质上,对于 Flag1
我想 return 0,对于 Flag2
我想 return 1,等等。除了使用带有 switch
语句的函数。
我想要这个是因为我有一个数据数组,函数的 return 值是这个数组的元素之一。 return 的哪个元素取决于传递给函数的标志。
我想要一种更简洁的方法来执行以下操作。 特别是如果我修改枚举,我不需要返回并修改此函数。
myobj* objects[3] = { obj1, obj2, obj3 };
myobj* GetObj(Flags FlagValue)
{
switch(FlagValue)
{
case Flag1:
return objects[0];
case Flag2:
return objects[1];
case Flag3:
return objects[2];
}
}
像这样的东西应该可以工作:
int iFlag = (int)FlagValue;
int ix = 0;
while (iFlag > 1) {
ix++;
iFlag = iFlag >> 1;
}
return objects[ix];
为了安全起见,添加对 FlagValue <= 0
或 FlagValue >= (sizeof(objects) / sizeof(objects[0]))
等非法输入的检查。
您需要的是一个计算枚举值中尾随零的函数。有很多方法可以做到这一点(参见 https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear),但大多数现代平台通常提供专门的 CPU 指令来完成这项工作。由于该语言没有相应的运算符,因此只能通过非标准的特定于编译器的方式访问该指令,例如 GCC 中的 __builtin_ctz
或 MSVC 中的 _BitScanReverse
。
但是,如果您专门使用编译时值,则更好的 C++ 解决方案将遵循
template <unsigned N> struct ctz {
static const unsigned value = ctz<N - 1>::value + 1;
};
template <> struct ctz<1> {
static const unsigned value = 0;
};
template <> struct ctz<0>; // Left undefined
...
cout << ctz<Flag2>::value << endl;
最简洁(也可能是正确)的方法是重新设计设计。 'flag' 并不是真正的标志 - 它是一个索引,因此根据索引进行编码。
enum Index { I1, I2, I3, INDEX_COUNT };
myobj* objects[INDEX_COUNT] = { obj1, obj2, obj3 };
myobj* GetObj(Index i)
{
assert(i < INDEX_COUNT);
return objects[i];
}