My suggestion is to unlearn the pre-processor macro magic tricks from C and similarly the template meta-programming and design pattern C++isms from C++.
Instead of dragging the cruft from C and C++, into another language, try to think from first principles and build your program from the pieces that Zig gives you, instead of re-inventing things like Singletons and similar bad patterns.
Personally I would urge you to get away from magic counters at build time and instead build / compose / declare things manually, it may require a bit more typing, but in the end it results in more readable and straightforward code, that you can easily reason about locally, without having to understand global side effects, of how some counter is manipulated, when it gets frozen etc.
Container level variables have static lifetime and are order-independent and lazily analyzed.
Zig is a lot more flexible than C or C++, so I don’t think you need to do these counter shenanigans.
If you have a bunch of things that should get an id then just accumulate all of those together with for example tuples, by combining tuples together with ++
and then when you have all of them use that to declare a static array that is initialized with that tuple. And then the counter just becomes the length of the resulting array and type-ids become the index in the array, if the array collects some kind of type information.
If you really want to do the counter manipulation things (not recommended), there is this topic: C/C++ macro challenge #1: BOOST_PP_COUNTER