So I've been using this code for generating such statements following This Reddit post:

#define LOOP(seq) END(A seq)
#define BODY(x) int x;
#define A(x) BODY(x) B
#define B(x) BODY(x) A
#define A_END
#define B_END
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END

LOOP((a)(b)(c)) // int a; int b; int c;

However, as the author mentioned, this doesn't let you pass a state from outside the loop, in my case I need to pass a suffix from outside, so something like LOOP( = 5; , (a)(b)(c))) Would expand to int a = 5; int b = 5; int c = 5; for example.

Is there a boilerplate free solution for this? if not what would be the more elegant boilerplate-ful one that is only needed for this specific use case? Thanks!

7 Replies 7

I think this should be posted as a "normal" (newly AKA Troubleshooting/Debugging) question rather than an open-ended "advice" one.

In any case - I wouldn't abuse macros like that, it will only make the code less readable and more error prone.

(this should have been a comment, but the new open-ended questions format does not support it at the moment).

My advice is not to abuse the preprocessor or the language in this way. Nobody will understand it, not even you after a while. Write your C code in C. Let your yea be yea, and your nay nay.

My advice is : DO NOT DO THIS!

Your code will become unreadable for anyone not knowing your macros.
Your goal is never to write the "least amount of code" it is to write readable code. And we all understand int a = 5; int b = 5; int c = 5;

I am really curious why you think this is a good idea in the first place

side note; when you're looking at sequentially named or numbered variables of the same type you're probably looking at a good place to use an array. Very often it'll make the code that follows easier to write.

It's worth noting this is for a shader resources declaration system that would be shared between the host and HLSL, so I don't exactly have options other than this or preprocessing shaders externally which I wouldn't want to do. I picked the simple usecase in the original post for simplicity, this is the actual usecase in HLSL:

#define BEGIN_BINDING_TABLE(name, slot)
#define END_BINDING_TABLE()

#define RESOURCE(slot, idx, descType, type, name) \
    type name : register( GET_REG_##descType(idx), space##slot );

Where I want to eliminate the need for entering the slot per resource, since the whole table is functionally supposed to be a single slot, and instead have BEGIN_BINDING_TABLE be a sort of macro with variadic args

Edit: I can't seem to delete this one for reposting as troubleshooting/debugging, so should this just remain?

There is no reason the C preprocessor has to be the only preprocessor used in building software. It is merely the preprocessor built into the compiler. A build system can execute any program as part of the build process. So you can use any scripting facility or write your own program to do whatever preprocessing you want. It can even be a program written in C that the build system compiles for the native system, links, and executes.

Write your own program that constructs the source code you want, then incorporate it into your build system, along with documentation explaining what it does and why you are using it.

Do not think that because the C preprocessor is built into the compiler, you must abuse it to generate source code.

To update, I ended up using MAP_UD from here, stripped down most of the header to just what MAP_UD relies on: https://github.com/swansontec/map-macro

I know this kind of preprocessor abuse is pretty questionable but I very much prefer it over adding dependencies into the chain especially that this is shared between host and shader code. Thanks everyone!

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.