Angenommen, wir haben ein solches Makro
#define FOO(type,name) type name
Was wir gerne gebrauchen könnten
FOO(int, int_var);
Aber nicht immer so einfach:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Natürlich könnten wir tun:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
das ist nicht sehr ergonomisch. Plus-Typ-Inkompatibilitäten müssen behoben werden. Irgendeine Idee, wie man das mit einem Makro löst?
c++
c
macros
c-preprocessor
Pop
quelle
quelle
Antworten:
Da Klammern Winkel auch (oder treten in) die Vergleichsoperatoren darstellen können
<
,>
,<=
und>=
können Makroerweiterung ignorieren keine Kommas innerhalb spitzen Klammern , wie es in Klammern der Fall ist. (Dies ist auch ein Problem für eckige Klammern und Klammern, obwohl diese normalerweise als ausgeglichene Paare auftreten.) Sie können das Makroargument in Klammern setzen:Das Problem ist dann, dass der Parameter innerhalb der Makroerweiterung in Klammern bleibt, wodurch verhindert wird, dass er in den meisten Kontexten als Typ gelesen wird.
Ein guter Trick, um dies zu umgehen, besteht darin, dass Sie in C ++ einen Typnamen aus einem in Klammern gesetzten Typnamen mithilfe eines Funktionstyps extrahieren können:
Da beim Bilden von Funktionstypen zusätzliche Klammern ignoriert werden, können Sie dieses Makro mit oder ohne Klammern verwenden, wenn der Typname kein Komma enthält:
In C ist dies natürlich nicht erforderlich, da Typnamen keine Kommas außerhalb von Klammern enthalten dürfen. Für ein sprachübergreifendes Makro können Sie also schreiben:
quelle
template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}
Angenommen, der gewünschte Code war folgender: Wenn ich diese Lösung hier anwende, werden die Strukturen hinter dem Makro zu abhängigen Typen, und das Typnamenpräfix ist jetzt für den Typ erforderlich. Sie können es hinzufügen, aber der Typabzug wurde unterbrochen, sodass Sie jetzt die Typargumente manuell auflisten müssen, um die Funktion aufzurufen. Am Ende habe ich die Methode von Temple verwendet, um ein Makro für das Komma zu definieren. Es sieht vielleicht nicht so hübsch aus, aber es hat perfekt funktioniert.[]
und{}
es funktioniert()
leider nur mit . Siehe: Es ist jedoch nicht erforderlich, dass eckige Klammern oder Klammern ausgeglichen sind ...#define PROTECT(...) argument_type<void(__VA_ARGS__)>::type
. Das Übergeben von Argumenten ist jetzt auch über mehrere Makros problemlos möglich. Für einfache Typen können Sie den PROTECT weglassen. Funktionstypen werden jedoch zu Funktionszeigern, wenn sie wieWenn Sie keine Klammern verwenden können und Mikes SINGLE_ARG-Lösung nicht mögen, definieren Sie einfach ein COMMA:
Dies ist auch hilfreich, wenn Sie einige der Makroargumente wie in
welche druckt
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.quelle
#define STRVX(...) STRV(__VA_ARGS__)
und#define STRV(...) # __VA_ARGS__
, dannstd::cout << STRV(type<A COMMA B>) << std::endl;
wird gedruckttype<A COMMA B>
undstd::cout << STRVX(type<A COMMA B>) << std::endl;
wird gedruckttype<A , B>
. (STRV
ist für "variadic stringify" undSTRVX
ist für "erweitertes variadic stringify".)COMMA
Makro überhaupt nicht . Damit bin ich gelandet.Wenn Ihr Präprozessor verschiedene Makros unterstützt:
Ansonsten ist es etwas langweiliger:
quelle
Einfach definieren
FOO
alsRufen Sie es dann immer in Klammern um das Typargument auf, z
Es kann natürlich eine gute Idee sein, die Aufrufe in einem Kommentar zur Makrodefinition zu veranschaulichen.
quelle
UNPACK
tun, wenn es so verwendet wird) UNPACK type name
? Warumtype
wird der Typ bei Verwendung korrekt abgerufen) UNPACK type name
? Was zum Teufel ist hier los?Es gibt mindestens zwei Möglichkeiten, dies zu tun. Zunächst können Sie ein Makro definieren, das mehrere Argumente akzeptiert:
Wenn Sie dies tun, werden Sie möglicherweise mehr Makros definieren, um mehr Argumente zu verarbeiten.
Zweitens können Sie das Argument in Klammern setzen:
Wenn Sie dies tun, stellen Sie möglicherweise fest, dass die zusätzlichen Klammern die Syntax des Ergebnisses durcheinander bringen.
quelle
Dies ist mit P99 möglich :
Der obige Code entfernt effektiv nur das letzte Komma in der Argumentliste. Überprüfen Sie mit
clang -E
(P99 erfordert einen C99-Compiler).quelle
Die einfache Antwort ist, dass Sie nicht können. Dies ist ein Nebeneffekt der Auswahl von
<...>
Vorlagenargumenten. Das<
und wird>
auch in unausgeglichenen Kontexten angezeigt, sodass der Makromechanismus nicht so erweitert werden kann, dass er sie wie Klammern behandelt. (Einige der Komiteemitglieder hatten sich beispielsweise für ein anderes Zeichen ausgesprochen(^...^)
, konnten jedoch die Mehrheit der Probleme nicht überzeugen<...>
.)quelle
(^...^)
Dies ist ein glückliches Gesicht :)