Generating function declaration using a macro iteration

c++, c++11, c-preprocessor, c99, variadic-macros

Solution

P99 has a macro that does exactly what you want, I think, namely `P99_PROTOTYPE`. It has a "signature" of

P99_PROTOTYPE(RT, NAME [, AT]*)

where `RT` is the return type (may be `void`) and `AT` are the argument types. The list of argument types may be empty, in which case it is substituted by `void`.

Beware that P99 is made for C99 and not for C++. You'll encounter particular difficulties if your arguments contain commas. C++'s syntax abuse of tokens `<` and `>` as bracketing expressions for templates is particularly bad for the preprocessor. C-preprocessor and C++ are basically incompatible languages on the syntax level.

P99 gets away from the difficulties that you are facing by detecting the number of arguments that the macro receives on a call and reacts differently on the border cases.

Problem

I'm trying to generate a function declaration using a macro ``` /* goal: generate int f(int a, float b) */ template<typename P> struct ptype; template<typename P> struct ptype<void(P)> { typedef P type; }; #define NAMEe #define COMMAe #define COMMA , #define NAME(N) N PARAMS #define PARAMS(P, ...) COMMA ## __VA_ARGS__ P NAME ## __VA_ARGS__ #define PARAM_ITER(P) P NAME #define PROTO(R, N, P) \ ptype<void R>::type N (PARAM_ITER P (,e)) PROTO((int), f, (int)(a)(float)(b)); ``` It will iteratively process the next `(name)` or `(type)` by `NAME` or `PARAMS` respectively, with the `...` having an empty macro argument. But GCC complains with ``` prototype.hpp:20:35: warning: ISO C99 requires rest arguments to be used ``` And clang complains with ``` ptype<void (int)>::type f (int aprototype.hpp:20:1: warning: varargs argument missing, but tolerated as an extension [-pedantic] ``` I think this happens because of the following ``` #define FOO(X, ...) FOO(A); ``` Because I'm not passing an argument for the `...` or each of those `(name)` or `(type)`. Is there any simple work around I can apply? I've now used a technique similar to the technique used by @James to find the length of a parameter list. If as second argument, instead of `O`, `ONT` is passed, I will print the comma and `NAME`. The following is the final solution: ``` /* goal: generate void f(int a, float b) */ template<typename P> struct ptype; template<typename P> struct ptype<void(P)> { typedef P type; }; #define TYPE_DO(X) X #define TYPE_DONT(X) #define TYPE_MAYBE(X, A, ...) TYPE_D ## A (X) #define COMMA_DO , #define COMMA_DONT #define COMMA_MAYBE(A, B, ...) COMMA_D ## B #define NAME_DO NAME #define NAME_DONT #define NAME_MAYBE(A, B, ...) NAME_D ## B #define NAME(N) N PARAMS #define PARAMS(...) COMMA_MAYBE(__VA_ARGS__,O,O) TYPE_MAYBE(__VA_ARGS__,O,O) \ NAME_MAYBE(__VA_ARGS__,O,O) #define PARAM_ITER(P) P NAME #define PROTO(R, N, P) \ ptype<void R>::type N (PARAM_ITER P (D,ONT)) ``` Test: ``` #define STR1(X) #X #define STR(X) STR1(X) int main() { // prints correctly std::cout << STR(PROTO((int), f, (int)(a)(float)(b))); } ```

Original source