C Macros: comment mapper une autre macro sur des arguments variadiques?

J’aimerais savoir comment appliquer une fonction unaire (ou une autre macro) à des arguments variadiques d’une macro, comme

int f(int a); #define apply(args...)  apply(a, b, c) 

qui se déroule

 f(a) f(b) f(c) 

Notez que le nombre d’arguments est inconnu.

Le code ci-dessous fonctionne pour ce que vous avez demandé avec jusqu’à 1024 arguments et sans utiliser d’autres éléments tels que boost. Il définit une macro EVAL(...) et aussi une macro MAP(m, first, ...) pour effectuer une récursion et utiliser pour chaque itération la macro m avec le paramètre suivant en first .

Avec cette utilisation, votre apply(...) ressemble à: #define apply(...) EVAL(MAP(apply_, __VA_ARGS__)) .

Il est principalement copié à partir de C pré-processeur Magic . C’est aussi très bien expliqué là-bas. Vous pouvez également télécharger ces macros d’aide comme EVAL(...) dans ce repository git . Le code contient également de nombreuses explications. Il est variadique, il faut donc le nombre d’arguments que vous voulez.

Mais j’ai changé les macros FIRST et SECOND car elle utilise une extension Gnu comme dans le source d’où je l’ai copiée. Ceci est dit dans les commentaires ci-dessous par @ HWalters :

Plus précisément, 6.10.3p4: “Sinon [la liste d’identifiants se termine par un …], il doit y avoir plus d’arguments dans l’appel que de parameters dans la définition de macro (à l’exclusion de …)”.

Partie principale de la fonction:

 int main() { int a, b, c; apply(a, b, c) /* Expands to: f(a); f(b); f(c); */ return 0; } 

Macro définitions:

 #define FIRST_(a, ...) a #define SECOND_(a, b, ...) b #define FIRST(...) FIRST_(__VA_ARGS__,) #define SECOND(...) SECOND_(__VA_ARGS__,) #define EMPTY() #define EVAL(...) EVAL1024(__VA_ARGS__) #define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__)) #define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__)) #define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__)) #define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__)) #define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__)) #define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__)) #define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__)) #define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__)) #define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__)) #define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__)) #define EVAL1(...) __VA_ARGS__ #define DEFER1(m) m EMPTY() #define DEFER2(m) m EMPTY EMPTY()() #define IS_PROBE(...) SECOND(__VA_ARGS__, 0) #define PROBE() ~, 1 #define CAT(a,b) a ## b #define NOT(x) IS_PROBE(CAT(_NOT_, x)) #define _NOT_0 PROBE() #define BOOL(x) NOT(NOT(x)) #define IF_ELSE(condition) _IF_ELSE(BOOL(condition)) #define _IF_ELSE(condition) CAT(_IF_, condition) #define _IF_1(...) __VA_ARGS__ _IF_1_ELSE #define _IF_0(...) _IF_0_ELSE #define _IF_1_ELSE(...) #define _IF_0_ELSE(...) __VA_ARGS__ #define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)()) #define _END_OF_ARGUMENTS_() 0 #define MAP(m, first, ...) \ m(first) \ IF_ELSE(HAS_ARGS(__VA_ARGS__))( \ DEFER2(_MAP)()(m, __VA_ARGS__) \ )( \ /* Do nothing, just terminate */ \ ) #define _MAP() MAP #define apply_(x) f(x); #define apply(...) EVAL(MAP(apply_, __VA_ARGS__)) 

Pour tester le développement des macros, il est utile d’utiliser gcc avec l’argument de ligne de commande -E :

 $ gcc -E srcFile.c 

parce que vous recevez des messages d’erreur concrets et comprenez ce qui se passe.

OMI impossible sauf si vous utilisez des astuces et des bidouilles horribles comme celle-ci

https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s

Et comme je le vois, elle appelle la même fonction, donc le type du paramètre est connu – pourquoi vous n’utilisez pas stdarg place.

Tout est possible en C si vous lancez assez de macros laides. Par exemple, vous pouvez avoir une macro laide comme une fonction:

 #include  int f (int a) { printf("%d\n", a); } #define SIZEOF(arr) (sizeof(arr) / sizeof(*arr)) #define apply(...) \ { \ int arr[] = {__VA_ARGS__}; \ for(size_t i=0; i 

Notez que 1) cela serait beaucoup mieux en tant que fonction variadique, et 2) ce serait encore mieux si vous vous débarrassiez complètement du non-sens variadique et réalisiez simplement une fonction telle

 int f (size_t n, int array[n])