In c ++ 03 und früheren Versionen verwende ich normalerweise folgenden Code, um die Compiler-Warnung über nicht verwendete Parameter zu deaktivieren:
#define UNUSED(expr) do { (void)(expr); } while (0)
Zum Beispiel
int main(int argc, char *argv[])
{
UNUSED(argc);
UNUSED(argv);
return 0;
}
Makros sind jedoch keine bewährte Methode für C ++. Erscheint eine bessere Lösung mit dem C ++ 11-Standard? Ich meine, kann ich Makros loswerden?
Danke für alles!
c++
c++11
unused-variables
inkooboo
quelle
quelle
(void)argc;
ist kürzer und klarer alsUNUSED(argc);
unused(argc, argv)
mittemplate<class... T> void unused(T&&...){}
. Klar, präzise und ohne Makros.void foo(int /*unused_arg*/, int used_arg)
Antworten:
Ich habe zu diesem Zweck eine Funktion mit einem leeren Körper verwendet:
template <typename T> void ignore(T &&) { } void f(int a, int b) { ignore(a); ignore(b); return; }
Ich erwarte von jedem ernsthaften Compiler, dass er den Funktionsaufruf optimiert und Warnungen für mich stummschaltet.
quelle
T
ist ein Vorlagenparameter,T&&
ist eine universelle Referenz, die an alles bindet.Sie können die Parameternamen einfach weglassen:
int main(int, char *[]) { return 0; }
Und im Fall von main können Sie die Parameter sogar ganz weglassen:
int main() { // no return implies return 0; }
Siehe "§ 3.6 Start und Beendigung" im C ++ 11-Standard.
quelle
main
können Sie die Parameter ganz weglassen. Und diereturn
Aussage im Übrigen.main
‚sreturn 0
in einem Testfall, aber fast immer die selbsterklärend schreibtreturn EXIT_SUCCESS
in Produktionscode. Das ist eine gute Praxis!Es ist die
<tuple>
in C ++ 11 , die Verwendung der bereit beinhaltetstd::ignore
Objekt, dass die uns erlauben , zu schreiben (sehr wahrscheinlich ohne Laufzeitaufwand zur Einführung):void f(int x) { std::ignore = x; }
quelle
Um diese Warnung zu "deaktivieren", vermeiden Sie am besten das Schreiben des Arguments. Schreiben Sie einfach den Typ.
void function( int, int ) { }
oder wenn Sie es vorziehen, kommentieren Sie es aus:
void function( int /*a*/, int /*b*/ ) { }
Sie können benannte und unbenannte Argumente mischen:
void function( int a, int /*b*/ ) { }
Mit C ++ 17 haben Sie den Attributbezeichner [[Maybe_unused]], wie:
void function( [[maybe_unused]] int a, [[maybe_unused]] int b ) { }
quelle
/* ... */
#if 0
Blöcken als Sonderfall, auch wenn sie nicht die vollständige Präprozessor-Intelligenz unterstützen.Nichts Äquivalentes, nein.
Sie stecken also bei den gleichen alten Optionen fest. Lassen Sie die Namen in der Parameterliste gerne ganz weg?
int main(int, char**)
Im speziellen Fall von
main
können Sie natürlich einfach die Parameter selbst weglassen:int main()
Es gibt auch die typischen implementierungsspezifischen Tricks wie GCCs
__attribute__((unused))
.quelle
Makros sind vielleicht nicht ideal, aber sie leisten gute Arbeit für diesen speziellen Zweck. Ich würde sagen, bleib bei der Verwendung des Makros.
quelle
MAYBE_UNUSED
diesem Grund würde ich das Makro aufrufen . Es ist mir normalerweise egal, ob ich gesagt habe "Mach dir keine Sorgen, wenn ich das unten nicht benutze", aber mach es trotzdem weiter.Was hast du gegen den alten und normalen Weg?
void f(int a, int b) { (void)a; (void)b; return; }
quelle
Es ist nichts Neues verfügbar.
Was für mich am besten funktioniert, ist das Auskommentieren des Parameternamens in der Implementierung. Auf diese Weise werden Sie die Warnung entfernen, behalten aber dennoch eine Vorstellung davon, was der Parameter ist (da der Name verfügbar ist).
Ihr Makro (und jeder andere Cast-to-Void-Ansatz) hat den Nachteil, dass Sie den Parameter nach Verwendung des Makros tatsächlich verwenden können. Dies kann die Wartung von Code erschweren.
quelle
Der Boost-Header
<boost/core/ignore_unused.hpp>
(Boost> = 1.56) definiert zu diesem Zweck die Funktionsvorlageboost::ignore_unused()
.int fun(int foo, int bar) { boost::ignore_unused(bar); #ifdef ENABLE_DEBUG_OUTPUT if (foo < bar) std::cerr << "warning! foo < bar"; #endif return foo + 2; }
PS C ++ 17 verfügt über das
[[maybe_unused]]
Attribut, Warnungen für nicht verwendete Entitäten zu unterdrücken.quelle
[[maybe_unused]]
ist expliziter Weg, derzeit am besten.Ich verwende dafür sehr gerne Makros, weil Sie so besser steuern können, wenn Sie verschiedene Debug-Builds haben (z. B. wenn Sie mit aktivierten Asserts erstellen möchten):
#if defined(ENABLE_ASSERTS) #define MY_ASSERT(x) assert(x) #else #define MY_ASSERT(x) #end #define MY_UNUSED(x) #if defined(ENABLE_ASSERTS) #define MY_USED_FOR_ASSERTS(x) x #else #define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x) #end
und dann benutze es wie:
int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar)) { MY_ASSERT(myChar < 12.0f); return myInt; }
quelle
Ich habe meine eigene Implementierung für zeitkritische Codesegmente. Ich habe eine Weile nach zeitkritischem Code für die Verlangsamung gesucht und festgestellt, dass diese Implementierung etwa 2% des zeitkritischen Codes verbraucht, den ich optimiert habe:
#define UTILITY_UNUSED(exp) (void)(exp) #define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1) #define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0
Der zeitkritische Code hat die
ASSERT*
Definitionen für Debug-Zwecke verwendet, aber in der Version wurde er eindeutig herausgeschnitten, aber ... Scheint, dass dieser Code etwas schnelleren Code erzeugt inVisual Studio 2015 Update 3
:#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0) #define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)
Der Grund ist im doppelten
false ?
Ausdruck. Es produziert irgendwie einen etwas schnelleren Code in der Version mit maximaler Optimierung.Ich weiß nicht, warum dies schneller ist (scheint ein Fehler bei der Compileroptimierung zu sein), aber es ist zumindest eine bessere Lösung für diesen Codefall.
Hinweis : Das Wichtigste dabei ist, dass ein zeitkritischer Code ohne die oben genannten Aussagen oder nicht verwendeten Makros in der Version langsamer wird . Mit anderen Worten, der doppelte
false ?
Ausdruck hilft überraschenderweise, einen Code zu optimieren.quelle
windows.h definiert UNREFERENCED_PARAMETER :
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
Sie könnten es also so machen:
#include <windows.h> #include <stdio.h> int main(int argc, char **argv) { UNREFERENCED_PARAMETER(argc); puts(argv[1]); return 0; }
Oder außerhalb von Windows:
#include <stdio.h> #define UNREFERENCED_PARAMETER(P) {(P) = (P);} int main(int argc, char **argv) { UNREFERENCED_PARAMETER(argc); puts(argv[1]); return 0; }
quelle
operator=
sie Nebenwirkungen haben kann.