6 ms·
The preprocessor trick of passing function macros as parameters is not that obscure. I have seen it used and I've used it myself. It is very useful when you hav
by elteto 7y ago
The preprocessor trick of passing function macros as parameters is not that obscure. I have seen it used and I've used it myself. It is very useful when you have a list of static "things" that you need to operate on.
Say I have a static list of names and I would like to declare some struct type for each name. I also would like to create variables of these structs at some point, and I would always do so for the entire block of names. You could do something like this:
#define apply(fn) \
fn(name1) \
fn(name2) \
fn(name3) \
...
fn(nameN)
#define make_struct(name) struct name##_t { ... }
#define make_variable_of(name) name##_t name;
...
apply(make_struct); // This defines all the structs.
void some_function(...) {
apply(make_variable_of); // And this defines one variable of each type.
}
Yes, it is not pretty (it is the C preprocessor after all), but it can be very useful and clean.
- jcranmer 7y agoI'd say none of the preprocessor stuff on this list is obscure--I've seen all of them in projects before.
- kzrdude 7y agoI would call that the X macro pattern, but the wiki article doesn't agree that it should pass the `fn` as the argument. Not sure if that's important.. https://en.wikipedia.org/wiki/X_Macro https://en.wikipedia.org/wiki/X_Macro
- elteto 7y agoMaybe at some point macros could not be passed as arguments? I honestly don’t know. Passing it as a parameter avoids all that define/undefine business.
- multun 7y agoIt can be both useful and obscure ;-) I realize it's not black magic, it's just uncommon. I used this trick to declare and generate code for an entire parser, it's lovely. I recently switched to the other style of C-macro though: #define X(A, B, C) ... #include <math/apply_operators.h> #undef X This style is less powerful but doesn't require the annoying \ at the end of lines.
- nsb1 7y agoHere's one of my favorites for dealing with logging repetitive enum names and the like: enum foo { FOO_THING_ONE, FOO_THING_TWO, FOO_THING_THREE, ... FOO_THING_SEVEN_HUNDRED }; // Using concatenate '##' and stringify '#' operators #define FANCYCASE(X) case FOO_THING_##X: str=#X; break const char *foo_to_str(enum foo myFoo) { char *str; switch(myFoo) { FANCYCASE(ONE); FANCYCASE(TWO); FANCYCASE(THREE); ... FANCYCASE(SEVEN_HUNDRED); } return str; }
- erichurkman 7y agoYou lose your ability to grep, though.