简体   繁体   中英

C++ enum by step

I'm trying to write the equivalent of an enum in C++ going in steps of eight instead of one, like

enum
{
    foo,
    bar = 8,
    baz = 16,
};

There will be a lot of entries, new ones will be added at intervals, and for clarity they really want to be written in an order other than order of entry, so it would be nice not to have to keep updating all the numbers by hand. I've tried mucking around with macro preprocessor tricks, but no dice so far. Is there a way to do this that I'm overlooking?

#define NEXT_ENUM_MEMBER(NAME) \
    NAME##_dummy, \
    NAME = NAME##_dummy - 1 + 8

enum MyEnum {
   Foo,
   NEXT_ENUM_MEMBER(Bar),
   NEXT_ENUM_MEMBER(Baz),
   ...
};

I prefer something like this:

enum {
    foo = (0 << 3),
    bar = (1 << 3),
    baz = (2 << 3),
};

It's not automated, but it doesn't require much thinking when adding a new enum constant.

I'm not quite sure what you're asking, but this approach will autogenerate values at steps of 8, and make it relatively easy to insert new values in the middle of the enum and have all the following values update to accomodate the change:

enum
  {
     foo,
     bar = foo + 8,
     baz = bar + 8
  }

After editing to add a "newvalue" you would have:

enum
  {
     foo,
     bar = foo + 8,
     newvalue = bar + 8,
     baz = newvalue + 8
  }

You could also use a "Step" constant so that you can (a) change your mind about the step later, and (b) stop anyone accidentally adding the wrong step:

const int EnumStep = 8;

  enum
  {
     foo,
     bar = foo + EnumStep,
     baz = bar + EnumStep 
  }

You could do the following:

#define STEP 8
#define ADD_ENUM(X, M) X = STEP * (M)
enum {
    ADD_ENUM(Foo, 0),
    ADD_ENUM(Bar, 1),
    ADD_ENUM(Baz, 2),
    //.. and so on
};

#include <stdio.h> 

enum{ foo = 0, bar = foo+8, baz = bar+8, };

int main(){ printf("foo: %i bar: %i baz: %i\n", foo, bar, baz ); }

Another approach which requires a separete header file for the enum , eg entries.h :

enum
{
    ENTRY(foo),
    ENTRY(bar),
    ENTRY(baz)
};

Then, you could use the following

#define ENTRY(E) _ ## E
#include "entries.h"
#undef ENTRY
#define ENTRY(E) E = _ ## E * 8
#include "entries.h"
#undef ENTRY

to generate

enum
{
    _foo,
    _bar,
    _baz
};

enum
{
   foo = _foo * 8,
   bar = _bar * 8,
   baz = _baz * 8
};
#define ENUM_ENTRY_PASTE( x )   x

#define ENUM_ENTRY_8_SPACING( x ) \
    x,      \
    ENUM_ENTRY_PASTE(x)2,   \
    ENUM_ENTRY_PASTE(x)3,   \
    ENUM_ENTRY_PASTE(x)4,   \
    ENUM_ENTRY_PASTE(x)5,   \
    ENUM_ENTRY_PASTE(x)6,   \
    ENUM_ENTRY_PASTE(x)7,   \
    ENUM_ENTRY_PASTE(x)8

Its not ideal as you'll have all those extras but you'll have your enums in the right place.

Yet another possibility that avoids using (MISRA-prohibited) ## operators or creating extra enums/entries would be to do:

#define USE_MYENUM(value) (value*8)

enum
{
    foo = 0,
    bar,
    baz
} MyEnum = bar;

CallFunction(USE_MYENUM(MyEnum));

Of course, it would probably be preferable to put USE_MYENUM (or more likely MyEnum*8 ) into CallFunction() so that the type checking is done.

Following Pavel Minaev solution and some other ideas from the answers, you could do something like this

#define BASE 0
#define STEP 8
#define NEXT_ENUM_MEMBER(NAME,PREVIOUS) \
    NAME = PREVIOUS + STEP

enum MyEnum {
   Foo = BASE,
   NEXT_ENUM_MEMBER(Bar, Foo),
   NEXT_ENUM_MEMBER(Baz, Bar)
};

Pros

  • Small memory footprint.
  • You can easily change the step and the base without update each entry.
  • You can easily delete and add an entry anywhere.

Cons

  • You must write the previous entry.
int foo, bar, baz;

baz = 
8 + bar =  
8 + foo; 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM