0

Not sure how to word this but, Is there any way to increment a macro?

I have several offset macros, the first defined offset must be zero, the next one must be 1, and so on. If I need to add an offset macro to the middle of the list, it can be cumbersome to increment all the offsets below it manually.

//How can I turn this...
              // v This number needs to increment by 1 (no matter the order)
#define OFFSET_X 0
#define OFFSET_Y 1
#define OFFSET_Z 2
#define OFFSET_W 3

//Into something like this... (order of macros swapped yet the numbering still goes from 0 to 3)
int num = 0; 
#define OFFSET_Z num++ // = 0  (was 2)
#define OFFSET_Y num++ // = 1  (was 1)
#define OFFSET_X num++ // = 2  (was 0)
#define OFFSET_W num++ // = 3  (was 3)
Zachwuzhere
  • 329
  • 3
  • 12
  • This is not like macros work. What you want is a variable; so use a variable. – Marcus Müller Jun 02 '18 at 21:51
  • 7
    Use an `enum` instead? – Mat Jun 02 '18 at 21:51
  • 1
    `__COUNTER__` is not standard afaik. – Marc Glisse Jun 02 '18 at 21:53
  • I know I can use variables but I just wanted to know if this could be done using macros. – Zachwuzhere Jun 02 '18 at 21:54
  • Look at Boost.Preprocessor, it provides things like that. – Marc Glisse Jun 02 '18 at 21:55
  • 4
    The best dreams I have are those of the death of macros. – DeiDei Jun 02 '18 at 21:55
  • 1
    https://www.boost.org/doc/libs/1_67_0/libs/preprocessor/doc/ref/inc.html – Maxim Egorushkin Jun 02 '18 at 21:58
  • @DeiDei "the death of macros". Why? They are so powerful! – Zachwuzhere Jun 02 '18 at 21:58
  • Impossible, unless you autogenerate a ton of `#if X == 1 #undef X #define X 2 #endif` for each macro, for each possible value. If you really want a compile-time counter, use stateful templates: https://stackoverflow.com/questions/44267673/is-stateful-metaprogramming-ill-formed-yet – HolyBlackCat Jun 02 '18 at 21:58
  • 4
    Looks like you’re reinventing enums. – molbdnilo Jun 02 '18 at 21:59
  • 1
    @Zachwuzhere simply because they are so very very often abused. The best use of them is actually not the "powerful" things you can do, imho, but simple non-recursive text replacement; the rest tends to wander off in the direction of abuse (and workarounds to mistakes done 30 years ago). – Marcus Müller Jun 02 '18 at 22:01
  • 1
    Maybe you can give some more detail, why you cannot use enum. If you can, it's probably the way you should go as it is a lot cleaner. – kiloalphaindia Jun 02 '18 at 22:03
  • I dont want the overhead of accessing an enum when I could just use a macro, aka copy paste at compile time – Zachwuzhere Jun 02 '18 at 22:05
  • 2
    There is no overhead to it. Its identical performancewise. (enums are compiletime constants) – kiloalphaindia Jun 02 '18 at 22:07
  • @Zachwuzhere Do not try to optimize based on guessing. That a) tends to cause needlessly poor code and b) doesn't even work. Unless you can measure the difference, it isn't real. – Baum mit Augen Jun 02 '18 at 22:12
  • @Zachwuzhere Declaring a list of constants with `enum` in C++ is equivalent to defining sequentially `constexpr int` values. There is no run-time overhead. Plus, `enum` is handled by the compiler, which checks types and other uses of the defined constants, rather than as macro by the preprocessor, which doesn't do such checks. – Edy Jun 02 '18 at 22:13
  • 1
    Ok, just tested the macro vs enum speed (100 million iterations), and it is the same speed. So I'll just use enums instead. Thanks. – Zachwuzhere Jun 02 '18 at 22:19

2 Answers2

1

With the original order,

#define OFFSET_X 0
#define OFFSET_Y (OFFSET_X + 1)
#define OFFSET_Z (OFFSET_Y + 1)
#define OFFSET_W (OFFSET_Z + 1)

or with the revised order in the second part of your post,

#define OFFSET_Z 0
#define OFFSET_Y (OFFSET_Z + 1)
#define OFFSET_X (OFFSET_Y + 1)
#define OFFSET_W (OFFSET_X + 1)

etc. Since all this gets evaluated at compile time, anyway, there's no perf hit.

Or you could write a code generator, if you're really bored, and have it generate the values for you.

Or just use an enum. This is what they're for, and they're treated as constants by the compiler, anyway - but you get compile-time error checking which is far less effective with macros.

BUT, a better solution may be constexpr added in C++11.

In any case, if you only have four of these, this is overkill.

3Dave
  • 28,657
  • 18
  • 88
  • 151
0

Just use an enum:

enum class offsets { 
    X = 0,
    Y = 1,
    Z = 2,
    W = 3 
};

and don't sweat it. Want auto-increments? Even easier:

enum class offsets { X = 0, y, z, w };

for the same effect.

Note I've suggested an enum class, so the usage is offsets::X, offsets::Y etc.

In some cases you may prefer an constexpr std::array, which you could then iterate over (something you can't do with macros or enums).

einpoklum
  • 118,144
  • 57
  • 340
  • 684