Vielleicht sind Funktionsüberladungen, Standardparameter, verschiedene Vorlagen oder möglicherweise die benannte Parametersprache das, wonach Sie suchen
Smoothware
Bitte aktualisieren Sie Ihre ausgewählte Antwort auf die hochstimmigen mit tatsächlichen Lösungen, nicht die niedrigstimmigen, die sagenNo you can't
Albert Renshaw
Antworten:
155
Hier ist eine Möglichkeit, dies zu tun. Die Liste der Argumente wird zweimal verwendet, um zuerst den Namen des Hilfsmakros zu bilden und dann die Argumente an dieses Hilfsmakro zu übergeben. Es verwendet einen Standardtrick, um die Anzahl der Argumente für ein Makro zu zählen.
Das ist ziemlich cool, aber ich glaube nicht, dass es funktionieren würde, wenn ich nur PRINT_STRING machen würde. In diesem Fall würde es keinen Standardausdruck geben (und das ist eigentlich der Fall, den ich verwenden möchte). Immer noch +1 für richtig cool.
Cenoc
2
funktioniert für mich in gcc (und es ist sehr klug!) :-) funktioniert aber nicht für mich in Visual Studio :-(
Tim Gradwell
3
@ TimGradwell - Dies liegt an einem Fehler im MSVC-Compiler, den sie erkannt, aber seit fast einem Jahrzehnt nicht mehr behoben haben. Es sind jedoch Problemumgehungen verfügbar .
BeeOnRope
Clever, funktioniert aber nicht für optionale variable Makroargumente, da Sie in "GET_4th_ARG" "Push-out" ausführen.
Searchengine27
wird das PRINT_STRING_MACRO_CHOOSERüberhaupt gebraucht? Kann ich direkt durch seinen inneren Körper ersetzen und das Ganze mit nennen (__VA_ARGS__)?
Herrgott
85
Mit großem Respekt an Derek Ledbetter für seine Antwort - und mit Entschuldigung für die Wiederbelebung einer alten Frage.
Ein Verständnis für das bekommen , was er tat , und an anderer Stelle auf der Fähigkeit , Kommissionierung bis der zu vorausgehen __VA_ARGS__mit ##mir erlaubt , mit einer Variation zu kommen ...
// The multiple macros that you would need anyway [as per: Crazy Eddie]#define XXX_0()<code for no arguments>#define XXX_1(A)<code for one argument>#define XXX_2(A,B)<code for two arguments>#define XXX_3(A,B,C)<code for three arguments>#define XXX_4(A,B,C,D)<code for four arguments>// The interim macro that simply strips the excess and ends up with the required macro#define XXX_X(x,A,B,C,D,FUNC,...) FUNC
// The macro that the programmer uses #define XXX(...) XXX_X(,##__VA_ARGS__,\
XXX_4(__VA_ARGS__),\
XXX_3(__VA_ARGS__),\
XXX_2(__VA_ARGS__),\
XXX_1(__VA_ARGS__),\
XXX_0(__VA_ARGS__)\
)
Für Nicht-Experten wie mich, die über die Antwort stolpern, aber nicht genau sehen können, wie sie funktioniert, werde ich die eigentliche Verarbeitung schrittweise durchführen, beginnend mit dem folgenden Code ...
XXX();
XXX(1);
XXX(1,2);
XXX(1,2,3);
XXX(1,2,3,4);
XXX(1,2,3,4,5);// Not actually valid, but included to show the process
Sie könnten einen eindeutigen Kompilierungsfehler erhalten, wenn Sie das ausgewählte Argument, bei dem es sich um einen MACRO-Namen handeln soll, mit # (dem Nummernzeichen) in einen String konvertieren und die ersten n Zeichen mit dem erwarteten Präfix vergleichen. Wenn keine Übereinstimmung vorliegt, drucken Sie eine Information aus Error.
AturSams
1
Wow, ich weiß nicht, ob das funktioniert, aber es ist zumindest sehr kreativ!
Begrenzte Versöhnung
4
Warum ist das erste Argument immer leer? warum können wir es nicht einfach weglassen: XXX_X(,##__VA_ARGS__,` ... XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `
rahman
2
Das leere erste Argument (Komma) ist wichtig. ## __ VA_ARGS__, wenn ein Komma vorangestellt ist - das Komma wird entfernt, wenn ## __ VA_ARGS__ zu nichts erweitert wird. Sie können es im Beispiel "Becomes ..." sehen, da die erste Zeile (keine Argumente) nur 6 Parameter enthält, der Rest jedoch 7. Dieser Trick stellt sicher, dass die Situation ohne Argumente funktioniert
David Sorkovsky
@Eric - Es liegt an einem Fehler in den Microsoft-Compilern, aber Sie können diese Frage zur Problemumgehung sehen.
BeeOnRope
31
C ++ - Makros haben sich nicht von C geändert. Da C keine Überladungs- und Standardargumente für Funktionen hatte, hatte es diese sicherlich nicht für Makros. Um Ihre Frage zu beantworten: Nein, diese Funktionen gibt es für Makros nicht. Sie können nur mehrere Makros mit unterschiedlichen Namen definieren (oder überhaupt keine Makros verwenden).
Als Randnotiz: In C ++ wird es allgemein als gute Praxis angesehen, sich so weit wie möglich von Makros zu entfernen. Wenn Sie solche Funktionen benötigen, besteht eine gute Chance, dass Sie Makros überbeanspruchen.
Beachten Sie, dass der Grund, warum es unmöglich ist, Makros zu "überladen", darin besteht, dass sie keine inhärenten Typen haben. Makros werden einfach erweitert.
mk12
2
Obwohl ich so wenig Makros wie möglich benutze, habe ich festgestellt, dass das Debuggen über Trace-Ausgabe mit Dingen wie __FILE__und __LINE__und so ziemlich einfacher wird ...
Bedingte Kompilierung und Debugging / Protokollierung ist die Domäne, in der Makros wirklich praktisch und legitim sind. Jeder ernsthafte Programmierer weiß es. Es empfiehlt sich, keine Makros zum Definieren von Konstanten zu verwenden und verrückte C-Level-Codierungsaufgaben zum Erstellen von Containervorlagen auszuführen. Ich wünschte, C ++ würde den Makros auch mehr Funktionen hinzufügen. Sie sind orthogonal zu Vorlagen. Am besten wären natürlich Codelets, mit denen ich dem Compiler Generatoren für domänenspezifische Sprachen (Aspekte) hinzufügen kann.
Lothar
1
Ich denke auch, dass dies keine gute Antwort ist, da ein Makro etwas völlig anderes ist als jede C ++ - Sprachoption, da es VOR dem Compiler behandelt wird. Sie können also andere Dinge tun, und kein Compiler oder Linker muss den Code optimieren, da er möglicherweise nicht optimiert werden muss.
Alabamajack
26
Mit größtem Respekt an Derek Ledbetter , David Sorkovsky , Syphorlate für ihre Antworten, zusammen mit der genialen Methode, leere Makroargumente von Jens Gustedt bei zu erkennen
Schließlich komme ich mit etwas heraus, das alle Tricks enthält, so dass die Lösung
Verwendet nur Standard-C99- Makros, um eine Funktionsüberladung zu erreichen, ohne dass eine GCC / CLANG / MSVC-Erweiterung beteiligt ist (dh Komma-Schlucken durch den spezifischen Ausdruck , ##__VA_ARGS__für GCC / CLANG und implizites Schlucken durch ##__VA_ARGS__für MSVC). --std=c99Wenn Sie möchten, können Sie das Fehlende an Ihren Compiler weitergeben =)
Funktioniert für Null-Argumente sowie für eine unbegrenzte Anzahl von Argumenten , wenn Sie es weiter erweitern, um es Ihren Anforderungen anzupassen
GNU / Linux + GCC (GCC 4.9.2 unter CentOS 7.0 x86_64)
GNU / Linux + CLANG / LLVM (CLANG / LLVM 3.5.0 unter CentOS 7.0 x86_64)
OS X + Xcode (XCode 6.1.1 unter OS X Yosemite 10.10.1)
Windows + Visual Studio (Visual Studio 2013 Update 4 unter Windows 7 SP1 64 Bit)
Für die Faulen springen Sie einfach zum letzten Teil dieses Beitrags, um die Quelle zu kopieren. Nachfolgend finden Sie eine ausführliche Erklärung, die hoffentlich allen Menschen hilft und sie inspiriert, die nach allgemeinen __VA_ARGS__Lösungen wie mir suchen . =)
So geht's Definieren Sie zunächst den Benutzer sichtbaren überlastete „Funktion“, nannte ich es create, und die tatsächliche Funktionsdefinition verwendet realCreate, und die Makrodefinitionen mit unterschiedlicher Anzahl von Argumenten CREATE_2, CREATE_1, CREATE_0, wie unten dargestellt:
Der MACRO_CHOOSER(__VA_ARGS__)Teil wird schließlich in die Makrodefinitionsnamen aufgelöst, und der zweite (__VA_ARGS__)Teil enthält deren Parameterlisten. So ein Anruf des Benutzers zu create(10)Entschlüssen zu CREATE_1(10), das CREATE_1kommt teilweise aus MACRO_CHOOSER(__VA_ARGS__), und das (10)Teil stammt aus dem zweiten(__VA_ARGS__) .
Der MACRO_CHOOSERverwendet den Trick, dass __VA_ARGS__der folgende Ausdruck , wenn er leer ist, vom Präprozessor zu einem gültigen Makroaufruf verkettet wird:
NO_ARG_EXPANDER __VA_ARGS__ ()// simply shrinks to NO_ARG_EXPANDER()
Genialerweise können wir diesen resultierenden Makroaufruf als definieren
#define NO_ARG_EXPANDER(),,CREATE_0
Beachten Sie die beiden Kommas, sie werden bald erklärt. Das nächste nützliche Makro ist
Wie der Makroname andeutet, müssen wir später die Anzahl der Argumente zählen. Hier kommt ein weiterer Trick: Der Präprozessor ersetzt nur den einfachen Text. Die Anzahl der Argumente eines Makroaufrufs wird lediglich aus der Anzahl der Kommas in den Klammern abgeleitet. Die durch Kommas getrennten tatsächlichen "Argumente" müssen keine gültige Syntax haben. Sie können ein beliebiger Text sein. Das heißt, im obigen Beispiel NO_ARG_EXPANDER 10 ()wird als 1 Argument für den mittleren Aufruf gezählt. NO_ARG_EXPANDER 20und20 () werden jeweils als 2 Argumente für den untersten Aufruf gezählt.
Wenn wir die folgenden Hilfsmakros verwenden, um sie weiter zu erweitern
Das anschließende ,Nach CREATE_1ist eine Problemumgehung für GCC / CLANG, die einen (falsch positiven) Fehler unterdrückt, der besagt, dass dies ISO C99 requires rest arguments to be usedbei der Übergabe -pedantican Ihren Compiler der Fall ist . Das FUNC_RECOMPOSERist eine Behelfslösung für MSVC, oder es kann nicht mehr Argumente zählt (dh Komma) in den Klammern der Makroaufrufe richtig. Die Ergebnisse werden weiter aufgelöst
Wie Sie vielleicht gesehen haben, besteht der letzte Schritt darin, einen Standard-Trick zum Zählen von Argumenten anzuwenden, um schließlich die gewünschten Namen der Makroversionen auszuwählen:
#define FUNC_CHOOSER(_f1, _f2, _f3,...) _f3
das löst die Ergebnisse auf
CREATE_0();
CREATE_1(10);
CREATE_2(20,20);
und gibt uns sicherlich die gewünschten, tatsächlichen Funktionsaufrufe:
Alles in allem ist die gesamte Quelle des Beispiels mit zwei Argumenten hier , wobei einige Anweisungen zur besseren Lesbarkeit neu angeordnet wurden :
Obwohl kompliziert, hässlich und den API-Entwickler belastend, gibt es eine Lösung zum Überladen und Festlegen optionaler Parameter von C / C ++ - Funktionen für uns Verrückte. Die Verwendung der ausgehenden überlasteten APIs wird sehr angenehm und angenehm. =)
Wenn es eine weitere mögliche Vereinfachung dieses Ansatzes gibt, lassen Sie es mich bitte unter wissen
@Phylliida ideone.com/jD0Hm5 - null bis fünf Argumente werden unterstützt.
xx
9
Für alle, die schmerzhaft nach einer VA_NARGS-Lösung suchen, die mit Visual C ++ funktioniert. Das folgende Makro hat in Visual C ++ Express 2010 für mich einwandfrei funktioniert (auch mit Null-Parametern!):
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...)bool(#__VA_ARGS__)?(VA_NUM_ARGS_IMPL_((__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1))):0
Wenn Sie ein Makro mit optionalen Parametern möchten, können Sie Folgendes tun:
Ich bekommeunresolved external symbol _bool referenced in function _main
Avidan Borisov
Ja, das kann in einigen Fällen passieren. Sie müssen sich bewusst sein, dass bool (#__ VA_ARGS__)? unterscheidet sich von den anderen Makros, da es zur Laufzeit ausgewertet wird. Abhängig von Ihrem Fall können Sie diesen Teil des Codes jedoch weglassen.
Syphorlat
2
Am Ende hatte ich tatsächlich pastebin.com/H3T75dcn, was perfekt funktioniert (auch 0 Argumente).
Avidan Borisov
Danke für den Link, und ja, du kannst es auch mit sizeof machen, aber für mich hat das in einigen Fällen nicht funktioniert, aber das Prinzip ist das gleiche (boolesche Auswertung).
Syphorlate
Können Sie einige Beispiele nennen, bei denen dies fehlschlägt?
Avidan Borisov
7
gcc/ g++unterstützt Varargs-Makros, aber ich denke nicht, dass dies Standard ist. Verwenden Sie es daher auf eigenes Risiko.
Sie sind Standard in C99 und werden auch zu C ++ 0x hinzugefügt.
Greyfade
5
#include<stdio.h>#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0#define PP_CONCAT(a,b) PP_CONCAT_(a,b)#define PP_CONCAT_(a,b) a ## b#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)#define THINK_0() THINK_1("sector zz9 plural z alpha")#define THINK_1(location) THINK_2(location,42)#define THINK_2(location,answer) THINK_3(location, answer,"deep thought")#define THINK_3(location,answer,computer) \
printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"" actually means will be build in %s\n",(answer),(computer),(location))int
main (int argc,char*argv[]){
THINK ();/* On compilers other than GCC you have to call with least one non-default argument */}
In Ihrem Code ist ein Fehler aufgetreten. bitte tun :%s/MY_MACRO_/THINK_/g:)
João Portela
Außerdem funktionierte es nicht mit null Argumenten unter Verwendung von g ++i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
João Portela
1
Für Variadiac-Makros gibt es keine Null-Argumente, da das leere Token ein gültiger Platzhalter ist.
Paul Fultz II
3
Dafür ist der Präprozessor nicht wirklich ausgelegt.
Wenn Sie jedoch mit einer gewissen Lesbarkeit in den Bereich der ernsthaft herausfordernden Makroprogrammierung einsteigen möchten, sollten Sie sich die Boost-Präprozessor-Bibliothek ansehen . Schließlich wäre es nicht C ++, wenn es nicht drei vollständig Turing-kompatible Programmierebenen gäbe (Präprozessor, Metaprogrammierung von Vorlagen und C ++ auf Basisebene)!
Als großer Fan von schrecklichen Makromonstern wollte ich Jason Dengs Antwort erweitern und sie tatsächlich nutzbar machen. (Zum Guten oder Schlechten.) Das Original ist nicht sehr gut zu verwenden, da Sie die große Alphabetsuppe jedes Mal ändern müssen, wenn Sie ein neues Makro erstellen möchten, und es ist noch schlimmer, wenn Sie eine andere Anzahl von Argumenten benötigen.
Also habe ich eine Version mit folgenden Funktionen erstellt:
0 Argument Fall funktioniert
1 bis 16 Argumente ohne Änderungen am chaotischen Teil
Einfach mehr Makrofunktionen zu schreiben
Getestet in gcc 10, clang 9, Visual Studio 2017
Momentan habe ich maximal 16 Argumente gemacht, aber wenn Sie mehr brauchen (wirklich jetzt? Sie werden nur albern ...), können Sie FUNC_CHOOSER und CHOOSE_FROM_ARG_COUNT bearbeiten und dann NO_ARG_EXPANDER einige Kommas hinzufügen.
Weitere Informationen zur Implementierung finden Sie in der hervorragenden Antwort von Jason Deng, aber ich werde den Code einfach hier einfügen:
#include<stdio.h>void realCreate(int x,int y){
printf("(%d, %d)\n", x, y);}// This part you put in some library header:#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16,...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F,...) FUNC_RECOMPOSER((__VA_ARGS__, \
F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))#define NO_ARG_EXPANDER(FUNC),,,,,,,,,,,,,,,,FUNC ## _0#define MACRO_CHOOSER(FUNC,...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))#define MULTI_MACRO(FUNC,...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)// When you need to make a macro with default arguments, use this:#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)#define CREATE_0() CREATE_1(0)#define CREATE_1(x) CREATE_2(x,0)#define CREATE_2(x, y) \
do{ \
/* put whatever code you want in the last macro */ \
realCreate(x, y); \
}while(0)int main(){
create();
create(10);
create(20,20);//create(30, 30, 30); // Compilation errorreturn0;}
Keines der oben genannten Beispiele (von Derek Ledbetter, David Sorkovsky und Joe D) zum Zählen von Argumenten mit Makros hat für mich mit Microsoft VCC 10 funktioniert. Das __VA_ARGS__Argument wird immer als einzelnes Argument betrachtet (Token-Izing mit)## oder nicht) Die Argumentverschiebung, auf die sich diese Beispiele stützen, funktioniert nicht.
Also, kurze Antwort, wie von vielen anderen oben angegeben: Nein, Sie können keine Makros überladen oder optionale Argumente verwenden.
Sie können, aber nur in C99 oder C ++ 11 (aufgrund von __VA_ARGS__). VC2010 ist C89 / C ++ 03 (wobei einige Teile von C ++ 11 auftauchen, aber noch nicht).
No you can't
Antworten:
Hier ist eine Möglichkeit, dies zu tun. Die Liste der Argumente wird zweimal verwendet, um zuerst den Namen des Hilfsmakros zu bilden und dann die Argumente an dieses Hilfsmakro zu übergeben. Es verwendet einen Standardtrick, um die Anzahl der Argumente für ein Makro zu zählen.
Dies erleichtert dem Aufrufer des Makros, nicht aber dem Schreiber.
quelle
PRINT_STRING_MACRO_CHOOSER
überhaupt gebraucht? Kann ich direkt durch seinen inneren Körper ersetzen und das Ganze mit nennen(__VA_ARGS__)
?Mit großem Respekt an Derek Ledbetter für seine Antwort - und mit Entschuldigung für die Wiederbelebung einer alten Frage.
Ein Verständnis für das bekommen , was er tat , und an anderer Stelle auf der Fähigkeit , Kommissionierung bis der zu vorausgehen
__VA_ARGS__
mit##
mir erlaubt , mit einer Variation zu kommen ...Für Nicht-Experten wie mich, die über die Antwort stolpern, aber nicht genau sehen können, wie sie funktioniert, werde ich die eigentliche Verarbeitung schrittweise durchführen, beginnend mit dem folgenden Code ...
Wird...
Welches wird nur das sechste Argument ...
PS: Entfernen Sie die #define für XXX_0, um einen Kompilierungsfehler zu erhalten [dh wenn eine Option ohne Argument nicht zulässig ist].
PPS: Es wäre schön, wenn die ungültigen Situationen (z. B. 5) dem Programmierer einen klareren Kompilierungsfehler geben würden!
PPPS: Ich bin kein Experte, daher freue ich mich sehr über Kommentare (gut, schlecht oder andere)!
quelle
XXX_X(,##__VA_ARGS__,` ...
XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `C ++ - Makros haben sich nicht von C geändert. Da C keine Überladungs- und Standardargumente für Funktionen hatte, hatte es diese sicherlich nicht für Makros. Um Ihre Frage zu beantworten: Nein, diese Funktionen gibt es für Makros nicht. Sie können nur mehrere Makros mit unterschiedlichen Namen definieren (oder überhaupt keine Makros verwenden).
Als Randnotiz: In C ++ wird es allgemein als gute Praxis angesehen, sich so weit wie möglich von Makros zu entfernen. Wenn Sie solche Funktionen benötigen, besteht eine gute Chance, dass Sie Makros überbeanspruchen.
quelle
__FILE__
und__LINE__
und so ziemlich einfacher wird ...Mit größtem Respekt an Derek Ledbetter , David Sorkovsky , Syphorlate für ihre Antworten, zusammen mit der genialen Methode, leere Makroargumente von Jens Gustedt bei zu erkennen
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
Schließlich komme ich mit etwas heraus, das alle Tricks enthält, so dass die Lösung
, ##__VA_ARGS__
für GCC / CLANG und implizites Schlucken durch##__VA_ARGS__
für MSVC).--std=c99
Wenn Sie möchten, können Sie das Fehlende an Ihren Compiler weitergeben =)Funktioniert einigermaßen plattformübergreifend , zumindest getestet
Für die Faulen springen Sie einfach zum letzten Teil dieses Beitrags, um die Quelle zu kopieren. Nachfolgend finden Sie eine ausführliche Erklärung, die hoffentlich allen Menschen hilft und sie inspiriert, die nach allgemeinen
__VA_ARGS__
Lösungen wie mir suchen . =)So geht's Definieren Sie zunächst den Benutzer sichtbaren überlastete „Funktion“, nannte ich es
create
, und die tatsächliche Funktionsdefinition verwendetrealCreate
, und die Makrodefinitionen mit unterschiedlicher Anzahl von ArgumentenCREATE_2
,CREATE_1
,CREATE_0
, wie unten dargestellt:Der
MACRO_CHOOSER(__VA_ARGS__)
Teil wird schließlich in die Makrodefinitionsnamen aufgelöst, und der zweite(__VA_ARGS__)
Teil enthält deren Parameterlisten. So ein Anruf des Benutzers zucreate(10)
Entschlüssen zuCREATE_1(10)
, dasCREATE_1
kommt teilweise ausMACRO_CHOOSER(__VA_ARGS__)
, und das(10)
Teil stammt aus dem zweiten(__VA_ARGS__)
.Der
MACRO_CHOOSER
verwendet den Trick, dass__VA_ARGS__
der folgende Ausdruck , wenn er leer ist, vom Präprozessor zu einem gültigen Makroaufruf verkettet wird:Genialerweise können wir diesen resultierenden Makroaufruf als definieren
Beachten Sie die beiden Kommas, sie werden bald erklärt. Das nächste nützliche Makro ist
so die Anrufe von
sind eigentlich erweitert auf
Wie der Makroname andeutet, müssen wir später die Anzahl der Argumente zählen. Hier kommt ein weiterer Trick: Der Präprozessor ersetzt nur den einfachen Text. Die Anzahl der Argumente eines Makroaufrufs wird lediglich aus der Anzahl der Kommas in den Klammern abgeleitet. Die durch Kommas getrennten tatsächlichen "Argumente" müssen keine gültige Syntax haben. Sie können ein beliebiger Text sein. Das heißt, im obigen Beispiel
NO_ARG_EXPANDER 10 ()
wird als 1 Argument für den mittleren Aufruf gezählt.NO_ARG_EXPANDER 20
und20 ()
werden jeweils als 2 Argumente für den untersten Aufruf gezählt.Wenn wir die folgenden Hilfsmakros verwenden, um sie weiter zu erweitern
Das anschließende
,
NachCREATE_1
ist eine Problemumgehung für GCC / CLANG, die einen (falsch positiven) Fehler unterdrückt, der besagt, dass diesISO C99 requires rest arguments to be used
bei der Übergabe-pedantic
an Ihren Compiler der Fall ist . DasFUNC_RECOMPOSER
ist eine Behelfslösung für MSVC, oder es kann nicht mehr Argumente zählt (dh Komma) in den Klammern der Makroaufrufe richtig. Die Ergebnisse werden weiter aufgelöstWie Sie vielleicht gesehen haben, besteht der letzte Schritt darin, einen Standard-Trick zum Zählen von Argumenten anzuwenden, um schließlich die gewünschten Namen der Makroversionen auszuwählen:
das löst die Ergebnisse auf
und gibt uns sicherlich die gewünschten, tatsächlichen Funktionsaufrufe:
Alles in allem ist die gesamte Quelle des Beispiels mit zwei Argumenten hier , wobei einige Anweisungen zur besseren Lesbarkeit neu angeordnet wurden :
Obwohl kompliziert, hässlich und den API-Entwickler belastend, gibt es eine Lösung zum Überladen und Festlegen optionaler Parameter von C / C ++ - Funktionen für uns Verrückte. Die Verwendung der ausgehenden überlasteten APIs wird sehr angenehm und angenehm. =)
Wenn es eine weitere mögliche Vereinfachung dieses Ansatzes gibt, lassen Sie es mich bitte unter wissen
https://github.com/jason-deng/C99FunctionOverload
Nochmals ein besonderer Dank an alle brillanten Menschen, die mich zu dieser Arbeit inspiriert und geführt haben! =)
quelle
Für alle, die schmerzhaft nach einer VA_NARGS-Lösung suchen, die mit Visual C ++ funktioniert. Das folgende Makro hat in Visual C ++ Express 2010 für mich einwandfrei funktioniert (auch mit Null-Parametern!):
Wenn Sie ein Makro mit optionalen Parametern möchten, können Sie Folgendes tun:
Das hat auch bei mir in vc funktioniert. Bei Nullparametern funktioniert dies jedoch nicht.
quelle
unresolved external symbol _bool referenced in function _main
gcc
/g++
unterstützt Varargs-Makros, aber ich denke nicht, dass dies Standard ist. Verwenden Sie es daher auf eigenes Risiko.quelle
HAFTUNGSAUSSCHLUSS: Meist harmlos.
quelle
:%s/MY_MACRO_/THINK_/g
:)i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
Dafür ist der Präprozessor nicht wirklich ausgelegt.
Wenn Sie jedoch mit einer gewissen Lesbarkeit in den Bereich der ernsthaft herausfordernden Makroprogrammierung einsteigen möchten, sollten Sie sich die Boost-Präprozessor-Bibliothek ansehen . Schließlich wäre es nicht C ++, wenn es nicht drei vollständig Turing-kompatible Programmierebenen gäbe (Präprozessor, Metaprogrammierung von Vorlagen und C ++ auf Basisebene)!
quelle
Sie wissen zum Zeitpunkt des Anrufs, wie viele Argumente Sie übergeben werden, sodass keine Überlastung erforderlich ist.
quelle
Prägnantere Version von Derek Ledbetters Code:
quelle
Als großer Fan von schrecklichen Makromonstern wollte ich Jason Dengs Antwort erweitern und sie tatsächlich nutzbar machen. (Zum Guten oder Schlechten.) Das Original ist nicht sehr gut zu verwenden, da Sie die große Alphabetsuppe jedes Mal ändern müssen, wenn Sie ein neues Makro erstellen möchten, und es ist noch schlimmer, wenn Sie eine andere Anzahl von Argumenten benötigen.
Also habe ich eine Version mit folgenden Funktionen erstellt:
Momentan habe ich maximal 16 Argumente gemacht, aber wenn Sie mehr brauchen (wirklich jetzt? Sie werden nur albern ...), können Sie FUNC_CHOOSER und CHOOSE_FROM_ARG_COUNT bearbeiten und dann NO_ARG_EXPANDER einige Kommas hinzufügen.
Weitere Informationen zur Implementierung finden Sie in der hervorragenden Antwort von Jason Deng, aber ich werde den Code einfach hier einfügen:
quelle
Sie können
BOOST_PP_OVERLOAD
aus einerboost
Bibliothek verwenden.Beispiel aus dem offiziellen Boost-Dokument :
quelle
Je nachdem, was Sie benötigen, können Sie dies mit var args mit Makros tun . Nun, optionale Parameter oder Makroüberladung, so etwas gibt es nicht.
quelle
Keines der oben genannten Beispiele (von Derek Ledbetter, David Sorkovsky und Joe D) zum Zählen von Argumenten mit Makros hat für mich mit Microsoft VCC 10 funktioniert. Das
__VA_ARGS__
Argument wird immer als einzelnes Argument betrachtet (Token-Izing mit)##
oder nicht) Die Argumentverschiebung, auf die sich diese Beispiele stützen, funktioniert nicht.Also, kurze Antwort, wie von vielen anderen oben angegeben: Nein, Sie können keine Makros überladen oder optionale Argumente verwenden.
quelle