2013-08-29 4 views
5

Ich habe folgendes Makro:C++ Vorprozess Makro mit 2 Argumenten

#define LOG(level,text) 

ich Makro definieren wollen, die sowohl Ebene und Text enthält:

#define MY_LOG_MESSAGE LEVEL1,"This is my log" 

so letztere kann ich laufen:

LOG(MY_LOG_MESSAGE); 

gcc Fragen Vorprozess Fehler:

error: macro "LOG" requires 2 arguments, but only 1 given

Irgendwelche Ideen?

+0

Was bedeutet 'log' erweitern können? – trojanfoe

+0

@trojanfoe Es fehlschlägt Vorverarbeitung – dimba

+0

Wenn dies tatsächlich über Protokollierung und nicht nur ein Beispiel ist, würde ich ernsthaft vorschlagen, eine ordnungsgemäße Protokollierungsbibliothek, z. [Boost.Log] (http://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/index.html), anstatt selbst zu rollen. Vor allem, wenn es auf dem Präprozessor basiert. –

Antwort

2

Wenn Sie sowieso eine Definition für jede Protokollmeldung verwenden können, vielleicht gefällt es das:

#define LOG_MY_MESSAGE LOG(LEVEL1, "This is my log")

Ein in Code d einfach als

LOG_MY_MESSAGE

+0

Dies könnte wahrscheinlich funktionieren, aber ich habe mehrere Makros als LOG(). In Ihrer Lösung muss ich Definieren Sie LOG_MY_MESSAGE pro LOG-Makro – dimba

+0

@dimba Nein, Sie können nicht die LOG() - Makros als Parameter verwenden, also verwenden wir '#define LOG_MY_MESSAGE (Logger) Logger (LEVEL1," Dies ist mein Log ")' In Ihrem Code können Sie schreiben 'LOG_MY_MESSAGE (LOG)' – sebi

+0

Es gibt mehrere ähnliche Lösung, aber Sie waren zuerst. – dimba

0

ja, definieren LOG wie folgt aus:

#define LOG(text) 

dann LOG erhalten nur 1 Parameter und Sie es mit Ihrer Nachricht

LOG(MY_LOG_MESSAGE); 
+0

LOG kann ich nicht neu definieren() - es ist nicht mein Code :( – dimba

+0

@dimba Ja können Sie; überschreiben Sie es einfach. – trojanfoe

0

verwendet Der Präprozessor von Anfang jeder Datei zu Ende geht es, sofort jede Makro mit der Ersatz-Token-Liste zu ersetzen. In Ihrem Fall wird LOG zuerst ersetzt, bevor MY_LOG_MESSAGE durch 2 Argumente ersetzt wird, also der Fehler.

0

MY_LOG_MESSAGE wird vom Präprozessor als ein Argument behandelt, da es eine Präprozessordirektive ist. LEVEL1,"This is my log" ist in Ihrem MY_LOG_MESSAGE enthalten und wird als ein einziges Präprozessor-Argument behandelt, wenn es in anderen Präprozessor-Direktiven verwendet wird.

Für einfache Funktionen wie

void DoLogging(Level level, const std::string& msg) 

Ihr Makro, wie Sie es erwarten, wird Aufruf behandelt. Also DoLogging(MY_LOG_MESSAGE) wird funktionieren. Es wird hier erweitert, weil es not als Argument einer anderen Präprozessor-Direktive verwendet wird, aber innerhalb einer real Funktion. Was könnte helfen, ist so etwas wie dieses:

#define MY_LOG_MESSAGE LOG(LEVEL1, "My message") 

Furhtermore, wenn es mehrere LOG() - Makros, wie Sie wies darauf hin, es ist nur als Parameter verwenden, von Ihnen MY_LOG_MESSAGE, wie folgt aus:

#define MY_LOG_MESSAGE(logger) logger(LEVEL1, "My message") 

In Ihrem Code rufen Sie einfach MY_LOG_MESSAGE(LOG)

1

Dies kann nicht so funktionieren. Für den Präprozessor geben Sie nur ein Argument an die LOG MACRO, wenn es zwei benötigt.

Sie können es lösen, indem sie etwas ein bisschen leichter machen:

#define MY_LOG_MESSAGE LOG(LEVEL1, "This is my log") 

Und es verwenden möchte:

MY_LOG_MESSAGE 

Erläuterung:

Im Fall:

#define LOG(level,text) 

#define MY_LOG_MESSAGE LEVEL1,"This is my log" 

LOG(MY_LOG_MESSAGE); 

Der Präprozessor wird Ihr Makro MY_LOG_MESSAGE nicht ersetzen, wenn es den Anruf an LOG sieht, wird es als Argument übergeben (wie eine Funktion).

Es ist erst danach, wenn der Präprozessor die LOG Makro ersetzen wird, dass es die Ersatz-Liste erneut gescannt werden, um zu sehen, ob es weitere Makro zu verarbeiten ist.

Aus dem Standard:

16.3.1 Argument substitution [cpp.subst]

  1. After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

Es wird gesagt, dass hier die als Argument übergeben Makros von einem anderen Makro nach erweitert werden, dass die Argumente für den Aufruf einer funktionsähnlichen Makros wurden identifiziert.

Dann können Sie auch Präprozessor zwingen, die Makros zu erweitern:

#define LOG(level, text) whatever 
#define MY_LOG_MESSAGE LEVEL1,"This is my log" 

#define LOG_LVL1(args) LOG(args) 
//    ^^^^  ^^^^ 
//   Pass a macro Will be expanded by the preprocessor here 
//       And LOG will receive the correct number of arguments 
LOG_LVL1(MY_LOG_MESSAGE) 
2

Sie haben die preprocesor zu überzeugen, das MY_LOG_MESSAGE Makro zu erweitern, bevor es LOG() zu erweitern versucht. Diese can be done durch einen einfachen Helfer Makro weiter:

#define LOG1(x) LOG(x) 

LOG1(MY_LOG_MESSAGE); 

Die Argumente für LOG1() sind in seinen Körper erweitert, für LOG() auf einen gültigen Aufruf führt.

2

Dies ist sehr ähnlich zu sth's answer, sondern ermöglicht es entweder mit einem oder zwei Parameter:

#define LOG_(level,text) implementation 
#define LOG(...) LOG_(__VA_ARGS__) 

#define MY_LOG_MESSAGE LEVEL1,"This is my log" 

LOG(MY_LOG_MESSAGE); 
LOG(LEVEL2, "Another log"); 

Der Punkt ist, dass LOG bewirkt, dass der Parameter vor dem Aufruf LOG_ erweitert werden, so dass es zwei Parameter in beiden Fällen geben .

0
#define ELOG(message) log(LEVEL_ERR,message) 
#define WLOG(message) log(LEVEL_WARN,message) 

so dass Sie es als

ELOG("This is error msg") oder WLOG("Warning msg")

vorausgesetzt, Sie haben eine Funktion

void log(int loglevel,char* msg)