Earlier quoted context omitted.
In actual production use, I think it could be better to write a separate program that will generate the code for you instead of using the C preprocessor (or use a language with this kind of introspection built in). However, using this hack lets you depend only on the facilities of the language, and that can be useful in simplifying the build process. Plus it was fun to create, too!
It can be a bit tricky if it isn't integrated with the build process.
Struct Iteration Through Abuse of the C Preprocessor
11–20 of 27 posts
Re: Struct Iteration Through Abuse of the C Preprocessor
#12You can do some interesting things using __COUNTER__ to make code using this less ugly. And if you're willing to use a small amount of C++ templates, you can make it possible to resolve all the iteration/member info at compile time to eliminate runtime overhead. I did both of these things for Grim Fandango for vertex/uniform buffers, so that the game could use buffers without caring about whether it was using OpenGL…
INTROSPECTION_DEFINE_STRUCT(S,
(int, anInt),
(bool, aBool),
(float, aFloat),
(double, aDouble),
(std::string, aString)
);
Then I create an instance of it: S s{ 23, true, 37.5f, 42.25, "String" };
And finally I can e.g. iterate over all fields and output their value using a generic lambda: forEachField(s, [](auto v) {
std::cout
There are also definitions for the field's type, offset, name etc. generated by the macro, so it's easy to create a binding for vertex attributes, map the struct to a table in Lua, serialize/deserialize it and so on.I'm really hoping C++ gets introspection soon. There are some proposals like https://isocpp.org/files/papers/n3996.pdf and a working group at https://groups.google.com/a/isocpp.org/forum/#!forum/reflect... but I'm not holding my breath for 2017.
Re: Struct Iteration Through Abuse of the C Preprocessor
#13Re: Struct Iteration Through Abuse of the C Preprocessor
#14Taking a step back: what you're trying to accomplish is code generation -- a program that generates code. From that perspective, why would you choose to write that program using the C preprocessor, when there are so many other nice languages around?
This is what I was going to suggest. C is even pretty easy to parse - you can just take the ready ANTLR grammar and use it to generate a parser in whatever language you want. Of course, he might go even one step further and specify the structs in some other language, then generate C source files from them, which would also allow you to easily generate consumers for that data format in other languages and now you're r…
http://clang.llvm.org/docs/LibASTMatchersReference.html
Now he has the actual compiler doing the work for him.
Re: Struct Iteration Through Abuse of the C Preprocessor
#15Earlier quoted context omitted.
It can be a bit tricky if it isn't integrated with the build process.
You can use e.g. cog which puts the generated code into the file itself: http://nedbatchelder.com/code/cog/ Then all you need to do is to remember to run the preprocessor after you've made a change to the generator code.
Re: Struct Iteration Through Abuse of the C Preprocessor
#16You can do some interesting things using __COUNTER__ to make code using this less ugly. And if you're willing to use a small amount of C++ templates, you can make it possible to resolve all the iteration/member info at compile time to eliminate runtime overhead. I did both of these things for Grim Fandango for vertex/uniform buffers, so that the game could use buffers without caring about whether it was using OpenGL…
I'm doing something similar in C++ for vertex attributes, integration with Lua et.al. First I define the struct: INTROSPECTION_DEFINE_STRUCT(S, (int, anInt), (bool, aBool), (float, aFloat), (double, aDouble), (std::string, aString) ); Then I create an instance of it: S s{ 23, true, 37.5f, 42.25, "String" }; And finally I can e.g. iterate over all fields and output their value using a generic lambda: forEachField(s, […
Re: Struct Iteration Through Abuse of the C Preprocessor
#17You can do some interesting things using __COUNTER__ to make code using this less ugly. And if you're willing to use a small amount of C++ templates, you can make it possible to resolve all the iteration/member info at compile time to eliminate runtime overhead. I did both of these things for Grim Fandango for vertex/uniform buffers, so that the game could use buffers without caring about whether it was using OpenGL…
Re: Struct Iteration Through Abuse of the C Preprocessor
#18Earlier quoted context omitted.
This is what I was going to suggest. C is even pretty easy to parse - you can just take the ready ANTLR grammar and use it to generate a parser in whatever language you want. Of course, he might go even one step further and specify the structs in some other language, then generate C source files from them, which would also allow you to easily generate consumers for that data format in other languages and now you're r…
Errr, he doesn't even need to use ANTLR, he can use clang, as a library. It can be linked into an app, has a nice AST, and matching abilities: http://clang.llvm.org/docs/LibASTMatchersReference.html Now he has the actual compiler doing the work for him.
I hate build systems.
Re: Struct Iteration Through Abuse of the C Preprocessor
#19 #define DEFINE_ENUM(name, variants) \
enum name { \
variants(DEFINE_ENUM_VARIANT_ITSELF) \
}; \
const char *repr_##name(enum name e) { \
switch (e) { \
variants(DEFINE_ENUM_VARIANT_REPR_CASE) \
default: return "?"; \
} \
}
#define DEFINE_ENUM_VARIANT_ITSELF(variant) variant,
#define DEFINE_ENUM_VARIANT_REPR_CASE(variant) \
case variant: return #variant;
// client code:
#define foo_variants(x) \
x(FOO_1) \
x(FOO_2)
DEFINE_ENUM(foo, foo_variants)Re: Struct Iteration Through Abuse of the C Preprocessor
#20why not using packed structure compiler feature?