Russell Trahan
Russell Trahan

Reputation: 792

C++ Get Bit Shift from Enum Value

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

Answers (3)

AnT stands with Russia
AnT stands with Russia

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

Richard Hodges
Richard Hodges

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

JimmyB
JimmyB

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

Related Questions