Du wird nicht so:
#define COMMA ,
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
DOCUMENTED_TYPEDEF(Foo<R COMMA S>,Bar)
Test:
$ gcc -E comma-macro.c
# 1 "comma-macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "comma-macro.c"
# 9 "comma-macro.c"
typedef Foo<R , S> Bar;
Makroargumentlisten für Klammern und Kommata analysiert werden, bevor eine Substitution stattfindet. Dann wird COMMA
im x
Argument ersetzt, und x
wird in den Makrokörper substituiert. Zu dieser Zeit ist das Auseinanderbrechen der Argumente getan; Es ist nicht relevant, dass COMMA
durch ein Komma-Punctuator-Token ersetzt wurde. Allerdings wird dieses Komma Argumente trennen, die in allen Makroaufrufen auftreten, die von diesem Makro generiert werden, also wenn diese geschützt werden müssen, brauchen Sie etwas verrückteres.
Sie können die COMMA
hinter einem funktionsähnliche Makro verstecken, sagen PAIR
:
#define COMMA ,
#define PAIR(A, B) A COMMA B
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
DOCUMENTED_TYPEDEF(PAIR(Foo<R, S>), Bar)
Auf den ersten Blick ist es attraktiver, aber es gibt wahrscheinlich Nachteile. Es ist mehr verschleiert. Der Leser fragt sich, gibt es eine Semantik hinter PAIR
? Wohingegen COMMA
für eine Semantik zu stumpf aussieht, und ihr Zweck ist wahrscheinlich sofort offensichtlich für jeden, der Kampfnarben von Kämpfen mit dem Präprozessor hat.
Über PAIR
können wir es vielleicht verstecken und enden mit einer Syntax wie in Zwols Antwort.Aber dann brauchen wir mehrere Varianten der DOCUMENTED_TYPEDEF
.
auch, nebenbei gesagt, lassen Sie uns die nutzlose COMMA
fallen, die nicht auf der rechten Seite eines Makros benötigt wird:
#define PAIR(A, B) A, B
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF_2(x2, y) class y : public PAIR x2 {};
#else
# define DOCUMENTED_TYPEDEF_2(x2, y) typedef PAIR x2 y;
#endif
DOCUMENTED_TYPEDEF_2((<R, S>), Bar)
$ gcc -std=c90 -E -Wall -pedantic comma-macro.c
# 1 "comma-macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "comma-macro.c"
# 11 "comma-macro.c"
typedef <R, S> Bar;
Das sieht aus wie es mit C99 Stil variadische Makros machbar sein kann . Dies kann jedoch die in den Kommentaren besprochene Übertragbarkeitsanforderung verletzen, ganz zu schweigen davon, dass dies C++ ist. Aus Gründen der zukünftigen Besucher:
#define PNEUMATIC_COMMA_GUN(A, ...) A, ## __VA_ARGS__
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(xv, y) class y : public PNEUMATIC_COMMA_GUN xv {};
#else
# define DOCUMENTED_TYPEDEF(xv, y) typedef PNEUMATIC_COMMA_GUN xv y;
#endif
DOCUMENTED_TYPEDEF((<R, S, T, L, N, E>), Bar)
$ gcc -std=c99 -E -Wall -pedantic comma-macro.c
# 1 "comma-macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "comma-macro.c"
# 9 "comma-macro.c"
typedef <R, S, T, L, N, E> Bar;
Ich vermute, dass es zu Problemen führen, weil das linke Argument X in die Position einer Erklärung Spezifizierer gesetzt wird. In einer C- und C++ - Deklaration verwenden Deklarationsbezeichner keine optionalen Klammern. Deklaratoren tun jedoch: 'int x;' und 'int (x);' sind das gleiche. '(int) x;' sieht aus wie ein Cast-Ausdruck. – Kaz
@Kaz Könnten Sie mit * always * leben, indem Sie Klammern um das Argument legen, das die Template-Parameter * und * enthält, wobei nur Compiler unterstützt werden, die C99 variadic-Makros implementieren? Wenn ja, gibt es einen Hack, der funktioniert. – zwol