2010-10-03 31 views
5

GCC se queja si hago esto:¿Puedo definir varias macros de preprocesador C con __VA_ARGS en el medio en lugar del final?

#define M(obj,met, ..., contents) obj##_##met(const void * self, __VA_ARGS__) { \ 
    contents \ 
    } 

mi Realizar estas 2 razones:

error: missing ')' in macro parameter list 
warning: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro 

Al parecer, C99 - estilo macros variadic esperan el paréntesis de cierre inmediatamente después de los puntos suspensivos, exigiendo de manera efectiva que el variadic lista ser los últimos argumentos de la macro. Necesito que esté en el medio para producir mi notación abreviada que se describe en la macro de arriba. ¿GCC es compatible con esta característica, utilizando otro estilo de macro variadic (no C99)? ¿Puedo emularlo haciéndolo de alguna otra manera? No quiero la lista variadic al final, hará que mi notación sea confusa. Y solo puedo usar GCC.

+0

* No quiero la lista variadic al final, hará que mi notación sea confusa. Y solo puedo usar GCC. * No tienes suerte. –

+0

Consulte [Boost.Preprocessor] (http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/index.html). Estoy casi seguro de que puede hacerlo siempre que deje de tratar de identificar el "contenido" como un argumento separado: utiliza una parte de las cosas del preprocesador para identificar el último argumento de los argumentos variables. La definición es un poco más compleja, por supuesto. –

Respuesta

7

No, no puedes. El ... debe aparecer al final.

Pero se podría definir M como

#define M(obj,met, ...) obj##_##met(const void * self, __VA_ARGS__) 

y utilizarlo como

void M(foo, bar, int x, char y, double z) { 
    content; 
} 
+0

:(eso es lo que temía. Gracias: D –

5

Tienes que poner la ... al final, pero utilizando LAST y POP_LAST macros, se puede mantener el mismo orden de argumentos para su macro y definirlo así:

#define M(obj,met, ...) obj##_##met(const void * self, POP_LAST(__VA_ARGS__)) { \ 
    LAST(__VA_ARGS__) \ 
    } 

He aquí cómo se puede definir estas macros:

/* This counts the number of args */ 
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N 
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1) 

/* This will let macros expand before concating them */ 
#define PRIMITIVE_CAT(x, y) x ## y 
#define CAT(x, y) PRIMITIVE_CAT(x, y) 

/* This will pop the last argument off */ 
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__) 
#define POP_LAST_1(x1) 
#define POP_LAST_2(x1, x2) x1 
#define POP_LAST_3(x1, x2, x3) x1, x2 
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3 
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4 
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5 
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6 
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7 

/* This will return the last argument */ 
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__) 
#define LAST_1(x1) x1 
#define LAST_2(x1, x2) x2 
#define LAST_3(x1, x2, x3) x3 
#define LAST_4(x1, x2, x3, x4) x4 
#define LAST_5(x1, x2, x3, x4, x5) x5 
#define LAST_6(x1, x2, x3, x4, x5, x6) x6 
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7 
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8 

Estas macros funcionarán para hasta 8 argumentos. Puede extenderlos fácilmente para manejar más si lo desea.

Cuestiones relacionadas