我的问题与代码的外观及其性能有关。
假设我有一个枚举:
typedef enum {
THIS_IS_A_VALUE1 = 65,
THIS_IS_A_VALUE2 = 10,
THIS_IS_A_VALUE3 = 45,
THIS_IS_A_VALUE4 = 5,
THIS_IS_A_VALUE5 = 7
} I_AM_AN_ENUM;
,我想检查某个变量是否包含枚举中的值之一: 我考虑了三种方法:
1。
int val;
if(val != THIS_IS_A_VALUE1 && val != THIS_IS_A_VALUE2 && val != THIS_IS_A_VALUE3...)
{
// val is different than all values
// do something
}
2。
if(val != THIS_IS_A_VALUE1)
{
// keep blank
}
else if(val != THIS_IS_A_VALUE2)
{
// keep blank
}
else if(val != THIS_IS_A_VALUE3)
{
// keep blank
}....
else
{
// val is different than all values
// do something
}
3。
switch(val)
{
case THIS_IS_A_VALUE1:
case THIS_IS_A_VALUE2:
case THIS_IS_A_VALUE3:
..
..
default:
// val is different than all values
// do something
}
说实话,我发现2和3很难看,尤其是当枚举中包含很多值时。 第一种方法也可能很丑陋,但比其他方法更好,尽管根据我的理解,使用很多&&可能会降低性能。
所以总结一下:可读性和性能对我来说非常重要, 我真的不确定哪个选项是最好的, 也许还有其他方法可以做到?
谢谢。
编辑:我忘了说值不是 连续的,是的,我不能真正更改它。
答案 0 :(得分:1)
我认为没有第四种方法会更好。我认为选项3是最好的选择,因为这样编译器可以检查您是否已处理所有情况。
当您决定向枚举添加选项时,这非常有用。然后,编译器会警告您,这样您就不会忘记包括新的情况。
答案 1 :(得分:1)
枚举与使用宏定义常量本质上是一样的,除了枚举将一组关联的常量包装为数据类型。这样可以使您的代码更具自记录性,但实际上并没有提供任何其他功能。
以下是您的问题引起的两种情况。
情况1 :枚举中的值不是连续的,表示
enum Foo { FIRST=0, MIDDLE=40, LAST=12 };
bool isInFoo(enum Foo x){
bool found = false;
switch(x){
case FIRST: found = true; break;
case MIDDLE: found = true; break;
case LAST: found = true; break;
}
return found;
}
这样,如果您不处理switch中的所有枚举,则会收到编译时警告。
情况2 :值是连续的。然后检查enum Bar x
是否在枚举中,您可以执行以下操作
enum Bar { FIRST=10, MIDDLE=11, LAST=12 };
bool isInBar(enum Bar x){ return x >= FIRST && x <= LAST; }
编辑:根据下面的评论,您可以将Bar
的“虚拟末尾”条目添加为OUT_OF_RANGE = LAST+1
,然后在功能isInBar()
中进行检查x小于OUT_OF_RANGE,这样,如果我们向枚举添加更多元素,则不必更改isInBar()函数,因为新添加的值应小于OUT_OF_RANGE。最后,取决于您是否包括在内。
请注意,在情况2中,枚举值不一定需要是连续的序列号,您可以将它们保留为所需的任何序列,但是随后需要相应地更改isInBar()
。
enum FooBar { FIRST=3, SECOND=6, THIRD=9, FOURTH=15, LAST=12 };
bool isInFooBar(enum FooBar x){
bool found = false;
for(int t=3;t<=15;t+=3)
if(x == t) {
found = true;
break;
}
return found;
}
答案 2 :(得分:0)
您可能希望封装检查逻辑并使用特殊名称来执行范围检查。采用这种方法可以提供一些非常好的集合逻辑操作,例如检查是否在这组值中或检查它是否与另一组相交,等等。
尽管我在C ++文件中使用Visual Studio 2005进行了编译,但我还没有测试过其中任何一个,但似乎可以使用它进行编译。换句话说,您可能需要对此进行一些调整。
typedef enum {
THIS_IS_A_VALUE1 = 65,
THIS_IS_A_VALUE2 = 10,
THIS_IS_A_VALUE3 = 45,
THIS_IS_A_VALUE4 = 5,
THIS_IS_A_VALUE5 = 7
} I_AM_AN_ENUM;
typedef enum {
IS_A_THIS_IS_A_VALUE1 = 0x01,
IS_A_THIS_IS_A_VALUE2 = 0x02,
IS_A_THIS_IS_A_VALUE3 = 0x04,
IS_A_THIS_IS_A_VALUE4 = 0x08,
IS_A_THIS_IS_A_VALUE5 = 0x10,
IS_A_THIS_IS_VALUE123 = 0x07, // bitwise Or of first three masks.
IS_A_THIS_IS_VALUE_ANY = 0x1f // is any of the values.
} IS_A_I_AM_ENUM;
struct {
I_AM_AN_ENUM eVal;
ULONG ulMask;
} testArray[] = {
{THIS_IS_A_VALUE1, IS_A_THIS_IS_A_VALUE1},
{THIS_IS_A_VALUE2, IS_A_THIS_IS_A_VALUE2},
{THIS_IS_A_VALUE3, IS_A_THIS_IS_A_VALUE3},
{THIS_IS_A_VALUE4, IS_A_THIS_IS_A_VALUE4},
{THIS_IS_A_VALUE5, IS_A_THIS_IS_A_VALUE5}
};
bool isInBar (I_AM_AN_ENUM x, ULONG ulCheckMask)
{
int i;
for (i = 0; i < sizeof(testArray)/sizeof(testArray[0]); i++) {
if (testArray[i].eVal == x) {
if (testArray[i].ulMask & ulCheckMask) return true;
else break;
}
}
return false;
}
// check a value against a range.
I_AM_AN_ENUM eVal = THIS_IS_A_VALUE3;
// check if eVal is Value3 or a Value 4
if (isInBar (eVal, IS_A_THIS_IS_A_VALUE3 | IS_A_THIS_IS_A_VALUE4)) // do something
if (isInBar (eVal, IS_A_THIS_IS_VALUE123 & ~IS_A_THIS_IS_A_VALUE1)) // do something
if (isInBar (eVal, IS_A_THIS_IS_VALUE_ANY)) // do something.