Können Makros überlastet werden durch die Anzahl der Argumente?
Wie funktioniert diese Arbeit? Wie kann ein C99/C++11 variadic Makros realisiert werden zu erweitern, um verschiedene Dinge, die allein auf der Grundlage, wie viele Argumente gegeben werden?
- Nicht beantworten wie es funktioniert, aber wenn es jemand braucht nur eine Umsetzung: boost preprocessor
Du musst angemeldet sein, um einen Kommentar abzugeben.
(Edit: Siehe am Ende für eine fertige Lösung.)
Um ein überladen makro, zuerst müssen wir ein makro, welches wählt zwischen verschiedenen Implementierungen. Dieses Teil keine variadischen makro. Dann eine Variable makro, welches generisch zählt seine Argumente produziert eine Auswahl. Anschließen das argument count in einen dispatcher erzeugt eine überladene makro.
Einschränkung: Dieses system kann nicht sagen, der Unterschied zwischen null und eins-Argumente, weil es ist keinen Unterschied zwischen " kein argument, und ein einzelnes leeres argument. Sie sehen beide wie
MACRO()
.Wählen Sie zwischen Implementierungen verwenden der makro-Kette Betreiber mit einer Reihe von function-like Makros.
Weil die
##
- operator unterdrückt makro Erweiterung Ihrer Argumente, es ist besser, wickeln Sie es in ein anderes makro.Zählen Argumente verwenden
__VA_ARGS__
zu verlagern Argumente wie, so (dies ist der clevere Teil):Bibliothek-code:
Verwendung:
VA_SIZE
. Es wäre zu erweitern, umGET_COUNT(x, 6, 5, 4, 3, 2, 1)
, die bricht diex
mit_1
, die6
mit_2
, und so weiter, und Sie sind Links mit1
wirdCOUNT
. Mit zwei Argumenten, ein mehr gedrängt auf und2
wirdCOUNT
.__VA_ARGS__
? Ich denke, dass einige Compiler bieten systeminterne Funktionen für Sie, und Steigern kann in der Regel auf gezählt werden, um zu verwenden Sie die entsprechende intrinsische vom compiler abhängig.Ich würde diesen post als Kommentar zu Potatoswatter post, aber es ist zu lange und erfordert ein code-listing.
Hier ist ein bisschen perl-code für das generieren einer Reihe von Makros, die gemeint sind, zu überladen Makros.
Hier ist die Ausgabe des Skripts:
Diese sind die (regelmäßig strukturierte Abschnitte von) Gruppen von makro-überlastungen, die verwendet werden, für die Erzeugung von
FOR_EACH
(ein.k.ein.FE
) Makros, die können versenden Sie einWHAT
makro Optional mit einer beliebigen Anzahl von Konstanten Argumenten (A1
,A2
...) neben eine beliebige Anzahl von Argumenten in einer Liste, zusammen mit einem index in die richtige Reihenfolge (eine naive Implementierung ohne Verwendung von so etwas wieSELECT
für überlastung ergeben würde Umgekehrt Indizes).Als Beispiel, der Letzte Abschnitt (der befristete Arbeitsplätze "base-case" - Teil des zweiten Blocks) sieht wie folgt aus:
Die Nützlichkeit dieser kann vielleicht in Frage gestellt (ich habe es gebaut, weil ich sah eine Verwendung für Sie...), und auch nicht, dass diese Antwort die OP ' s Frage direkt (in der Tat, es irgendwie das Gegenteil ist der Fall -- ein foreach-Konstrukt wird die gleichen Sache für alle variadic Argumente...), aber ich dachte nur, dass die Technik ist ziemlich interessant (wie auch äußerst erschreckend in gewisser Weise) und ermöglicht eine Recht ausdrucksstarke Leistung mit dem Präprozessor und es wird möglich sein, erzeugen sehr effizienten Maschinencode in dieser Art und Weise. Ich denke, es dient auch als ein ergreifendes Beispiel dafür, warum ich persönlich denke, dass der C-Präprozessor-der hat immer noch Raum für Verbesserungen.
Damit meine ich, dass der C-Präprozessor ist ein absolutes Greuel, und wir sollten wohl verschrotten und von vorne anfangen 🙂
Folgenden ist eine Verbesserung auf Potatoswatter Antwort, die kann differenzieren zwischen null und einem argument.
Kurz gesagt, wenn die
__VA_ARGS__
leer ist,EXPAND __VA_ARGS__ ()
innenVA_SIZE
makro wirdEXPAND ()
und substituiert ist mit 6 Kommas. AlsoVA_SIZE...
wirdCOMPOSE( GET_COUNT, (,,,,,, , 0, 6, 5, 4, 3, 2, 1) )
, und das wirdGET_COUNT (,,,,,, , 0, 6, 5, 4, 3, 2, 1)
und gibt 0 zurück.Auf der anderen Seite, wenn
__VA_ARGS__
ist zBint, 5
,EXPAND __VA_ARGS__ ()
wirdEXPAND int, 5 ()
. AlsoVA_SIZE...
wirdCOMPOSE( GET_COUNT, (EXPAND int, 5 (), 0, 6, 5, 4, 3, 2, 1) )
, die wirdGET_COUNT (EXPAND int, 5 (), 0, 6, 5, 4, 3, 2, 1)
und zurück 2, wie beschrieben in Potatoswatter Antwort.Bekam ich die
EXPAND
Idee von Jason Dang Antwort.Bibliothek-code:
Verwendung:
iso c99 requires rest arguments to be used
. Und ich muss mit dem gcc-pedantic
Schalter für das Projekt Gründen.Obwohl es schon beantwortet, ich habe bereit eine sehr kurze version. Hoffe es kann helfen.
Umsetzung
Anpassung
Nutzung
__
ich habe absichtlich gehalten (siehe den Kommentar), weil in der Regel Menschen haben eineCONCATE
&CONCATE_
Kombination Ihrer eigenen für die Verkettung von 2 Zeichenketten, daher wird dieser Teil sowieso Weg. Denke, von, dass '__' als Platzhalter zur Vereinfachung des Verständnisses.__
ist ein Fehler; es ist reserviert für den compiler Implementierer und nicht erlaubt für die Benutzer.Erweiterte ich die Lösung von Potatowatter zu vermeiden, die
iso c99 requires rest arguments to be used
Problem, wenn der gcc-compiler-Schalter-pedantic
im Einsatz ist.Bibliothek
Anpassung
Nutzung