2010-10-03 40 views
5

GCC se plaint si je fais ceci:Puis-je définir des macros préprocesseur C variées avec __VA_ARGS au milieu de la fin?

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

me donner ces 2 raisons:

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

Apparemment, C99 - le style des macros variadique attendent la parenthèse fermante immédiatement après les points de suspension, exigeant efficacement que le variadique liste soit les derniers arguments de la macro. J'ai besoin qu'il soit au milieu pour produire ma notation abrégée décrite dans la macro ci-dessus. GCC prend-il en charge cette fonctionnalité, en utilisant un autre style de macro variadique (non-C99)? Puis-je l'imiter en le faisant d'une autre manière? Je ne veux pas la liste variée à la fin, cela rendra ma notation déroutante. Et je ne peux utiliser que GCC.

+0

* Je ne veux pas la liste variadique à la fin, cela rendra ma notation confuse. Et je ne peux utiliser GCC. * Vous n'avez pas de chance. –

+0

Consultez [Boost.Preprocessor] (http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/index.html). Je suis presque certain que vous pouvez le faire à condition d'arrêter d'essayer d'identifier 'content' comme un argument séparé - vous utilisez une partie du contenu du préprocesseur pour identifier le dernier argument des arguments de la variable. La définition est un peu plus complexe, bien sûr. –

Répondre

7

Non, vous ne pouvez pas. Le ... doit apparaître à la fin.

Mais vous pouvez définir M comme

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

et l'utiliser comme

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

:(c'est ce que je craignais Merci: D –

5

Vous devez mettre le ... à la fin, mais en utilisant LAST et POP_LAST macros, vous pouvez garder le même ordre des arguments pour votre macro et le définir comme ceci:

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

Heres comment vous pouvez définir ces 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 

Ces macros fonctionneront jusqu'à 8 arguments. Vous pouvez facilement les étendre pour gérer plus si vous le souhaitez.