views:

129

answers:

2

Is it "safe" to give macros names as arguments to other macros to simulate higher order functions?

I.e. where should I look to not shoot myself in the foot?

Here are some snippets:

#define foreach_even(ii, instr) for(int ii = 0; ii < 100; ii += 2) { instr; }
#define foreach_odd(ii, instr)  for(int ii = 1; ii < 100; ii += 2) { instr; }

#define sum(foreach_loop, accu) \
  foreach_loop(ii, {accu += ii});

int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);

What about partial application, can I do that? :

#define foreach(ii, start, end, step, instr) \
  for(int ii = start; ii < end; ii += step) { instr; }

#define foreach_even(ii, instr) foreach(ii, 0, 100, instr)
#define foreach_odd(ii, instr)  foreach(ii, 1, 100, instr)

#define sum(foreach_loop, accu) \
  foreach_loop(ii, {accu += ii});

int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);

And can I define a macro inside a macro?

#define apply_first(new_macro, macro, arg) #define new_macro(x) macro(arg,x)
+3  A: 

If you're into using preprocessor as much as possible, you may want to try boost.preprocessor.

But be aware that it is not safe to do so. Commas, for instance, cause a great number of problems when using preprocessors. Don't forget that preprocessors do not understand (or even try to understand) any of the code they are generating.

My basic advice is "don't do it", or "do it as cautiously as possible".

Benoît
+1  A: 

I've implemented a rotten little unit testing framework entirely in c-preprocessor. Several dozen macro, lots of macro is an argument to another macro type stuff.

This kind of thing is not "safe" in a best-practices sense of the word. There are subtle and very powerful ways to shoot yourself in the foot. The unit testing project is a toy that got out of hand.

Don't know if you can nest macro definitions. I doubt it, but I'll go try...gcc doesn't like it, and responds with

nested_macro.cc:8: error: stray '#' in program
nested_macro.cc:3: error: expected constructor, destructor, or type conversion before '(' token
nested_macro.cc:3: error: expected declaration before '}' token

Self plug: If you're interested the unit testing framework can be found at https://sourceforge.net/projects/dut/

dmckee