Reputation: 792
Let's say I have an enum which is used for flags, i.e.
enum Flags { Flag1 = 1 << 0, Flag2 = 1 << 1, Flag3 = 1 << 2 };
If I am given a Flags
value, I would like to know what the bit shift of the value is. Essentially, for Flag1
I would like to return 0, for Flag2
I would like to return 1, etc. Can anyone think of a way to do this other than using a function with a switch
statement.
I am wanting this because I have an array of data and the return value of a function is one of the elements of this array. Which element to return is dependent on which flag is passed to the function.
I would like a more concise way of doing the following. Especially one where if I modify the enum I do not need to go back and modify this function.
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];
}
}
Upvotes: 1
Views: 471
Reputation: 320421
What you need is a function that counts trailing zeros in your enum values. There are quite a few methods that can do this (see https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear), but most modern platforms typically provide a dedicated CPU instruction that does exactly that. Since the language has no corresponding operator, access to that instruction is only available through non-standard compiler-specific means, like __builtin_ctz
in GCC or _BitScanReverse
in MSVC.
However, if you are exclusively working with compile-time values a better C++ solution would be something along the lines of
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;
Upvotes: 5
Reputation: 69864
The most concise (and probably correct) way is to re-engineer the design. The 'flag' is not really a flag - it's an index, so code in terms of an index.
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];
}
Upvotes: 2
Reputation: 12610
Something like this should work:
int iFlag = (int)FlagValue;
int ix = 0;
while (iFlag > 1) {
ix++;
iFlag = iFlag >> 1;
}
return objects[ix];
To be safe, add checks for illegal input like FlagValue <= 0
or FlagValue >= (sizeof(objects) / sizeof(objects[0]))
.
Upvotes: 1