5

I want to have a single macro call which takes in multiple function pointers, and each function pointer is called by a second macro which is a function declaration.

I want two macros on the form

#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) (???)

which is called as such

FUNCTION_DEFS(
    myFunc1,
    myFunc2,

    otherFunc1,
    otherFunc2,

    defaultFunc
)

which expands into

FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)

FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)

FUNCTION_DEF(defaultFunc)

In other words, this single call to FUNCTION_DEFS expands into function declarations of all the variadic arguments.

Currently I'm just skipping the first step and calling FUNCTION_DEF on each function pointer, however a solution to this would be great.

Is this possible?

Edit:

Thanks to @Vality for introducing me to X-Macro. I found this post "Real-world use of X-Macros" which was exactly what I needed.

Community
  • 1
  • 1
edvardsp
  • 133
  • 8
  • Yep. With e.g. Boost.PP. – Columbo Jul 27 '15 at 13:51
  • @Columbo: boost in C? – too honest for this site Jul 27 '15 at 13:52
  • @Olaf From the documentation: *"The Boost Preprocessing library is a library of macros, with support for preprocessor metaprogramming. The library supports both C++ and C compilation."* – Columbo Jul 27 '15 at 13:54
  • Ok, sorry, dod not know boost is two parts: preprocessing and compilation lib. (I did not know how to interpret the "PP" in your first comment) – too honest for this site Jul 27 '15 at 13:57
  • You cannot do this with a standard C preprocessor. Not for *any* number of parameters. But you can do it if you assume there won't be more than N parameters for your variadic macro (see [here](http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible) for reference) – Eugene Sh. Jul 27 '15 at 14:06
  • @Columbo, forgot to mention this is on an embedded solution where i can not use third party libraries/headers such as Boost. – edvardsp Jul 27 '15 at 14:10
  • 3
    @Olaf for completeness, Boost is not a library but a collection of independent libraries. Some are header-only, some need object files, and some are also C. – Quentin Jul 27 '15 at 14:31
  • @edvardsp I'm curious, how is the target platform relevant to whether you can use Boost.PP headers so you don't have to type the boilerplate yourself ? – Quentin Jul 27 '15 at 14:40
  • @Quentin, I'm interning in a company where I'm working on an embedded solution in a closed environment, which means I have to create all of the code. – edvardsp Jul 27 '15 at 14:49
  • @Quentin: Thank you! I just know boost from hearsay long time ago. Never cared about since its early starts. May be it's time to get an update. – too honest for this site Jul 27 '15 at 14:57

2 Answers2

3

I do not believe what you want precisely is possible using the standard C preprocessor. However a similar solution can be accomplished with X macros.

To do the equivalent of your code using them you would first define the function list as an X macro:

#define FUNCTION_LIST_A \
    X(myFunc1) \
    X(myFunc2) \
    X(otherFunc1) \
    X(otherFunc2) \
    X(defaultFunc)

Then to instantiate these functions with a specific macro you would then define the macro to perform on each function:

#define X(name) FUNCTION_DEF(name)
FUNCTION_LIST_A
#undef X

Which will then expand to:

FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)
FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)
FUNCTION_DEF(defaultFunc)

Hopefully this is useful and close to what you want. Admittedly the syntax is significantly different but if what you wish to accomplish is to apply a chosen function or macro to a whole list of data (in this case function pointers) this is the most idiomatic way I know of to do so using the c preprocessor.

Vality
  • 6,577
  • 3
  • 27
  • 48
  • 2
    Good answer, however it *is* possible in standard PP. You probably want to let the Boost.PP guys get their hands dirty with the plumbing, though :p – Quentin Jul 27 '15 at 14:33
  • @Quentin You are absolutely correct about boost being able to do this, and probably a fair bit more elegantly, however I am trying to work around the ops requirement not to use an external preprocessor which they mentioned in a comment "forgot to mention this is on an embedded solution where i can not use third party libraries/headers such as Boost". Still, yeah, a different prepocessor is the best solution. – Vality Jul 27 '15 at 14:36
  • Boost is *not* an external preprocessor. BoostPP is a pure .h solution; anything in it can be done again in pure user code. – Alex Celeste Jul 27 '15 at 14:38
  • @Leushenko If you know how, please do feel free to add another answer for BoostPP, I do not have enough knowledge of it to accomplish this but if you can use it to make a better solution it is worth telling the op. – Vality Jul 27 '15 at 14:40
  • 1
    @Vality, this is exactly what I want! This also gives me great re-usability since I also need to make a function pointer table out of the same list, which I can do with this setup. Thanks! – edvardsp Jul 27 '15 at 14:46
1

There are many ways to do this. The most simple is to predefine a version of the loop for each possible length (building on smaller versions), and simply choose the right one based on the number of arguments to iterate over:

#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N

#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__

#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)

#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//...etc

#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) M_FOR_EACH(FUNCTION_DEF, __VA_ARGS__)

You could also cook up a more general solution using traditional recursive techniques, but that usually requires a support library (such as [1], [2]) to provide the mechanism since directly-defined macros don't support recursion.

This is because all looping in the preprocessor has to have a predetermined upper limit, a a consequence of no direct macro recursion: you can either hard-code that limit into your loop implementation in simple cases like the above code, or you can have the recursion-driver underlying your loop-construction operators contain the limit instead, and provide N iterations to constructs that request them (the advantage of the latter is that it lets you centralize, and then forget about, the limit as long as it's high enough, e.g. Order-PP has a limit in the billions of iterations that you won't ever hit in practice).

Community
  • 1
  • 1
Alex Celeste
  • 12,824
  • 10
  • 46
  • 89