Declaración de función de generación utilizando una macro iteración

Estoy tratando de generar una declaración de función usando una 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));

Procesará iterativamente la próxima(name) o(type) porNAME oPARAMS respectivamente, con la... teniendo un argumento macro vacío. Pero GCC se queja con

prototype.hpp:20:35: warning: ISO C99 requires rest arguments to be used

Y clang se queja con

ptype<void (int)>::type f (int aprototype.hpp:20:1: warning: varargs argument missing, but tolerated as an extension [-pedantic]

Creo que esto sucede debido a lo siguiente

#define FOO(X, ...)
FOO(A);

Porque no estoy pasando un argumento por el... o cada uno de esos(name) o(type). ¿Hay alguna solución simple para aplicar?

Ahora he usado una técnica similar a la técnica utilizada por @James para encontrar la longitud de una lista de parámetros. Si como segundo argumento, en lugar deO, ONT se pasa, imprimiré la coma yNAME. La siguiente es la solución final:

/* 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))

Prueba

#define STR1(X) #X
#define STR(X) STR1(X)

int main() {
  // prints correctly
  std::cout << STR(PROTO((int), f, (int)(a)(float)(b)));
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta