Nicht verwendeter Parameter in c ++ 11

79

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!

inkooboo
quelle
11
Sicher. Schalten Sie die Warnung aus.
Pete Becker
64
Nein! TU das nicht!
Leichtigkeitsrennen im Orbit
9
Wie viel besser ist dieses Makro, als es inline zu erweitern? (void)argc;ist kürzer und klarer alsUNUSED(argc);
David Rodríguez - Dribeas
22
Ich mag unused(argc, argv)mit template<class... T> void unused(T&&...){}. Klar, präzise und ohne Makros.
Xeo
19
@MadScientist, aber Sie können ein unbenanntes Argument hinterlassen oder sogar nur den Namen auskommentieren. void foo(int /*unused_arg*/, int used_arg)
Kassak

Antworten:

40

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.

Verrückter Wissenschaftler
quelle
20
Wann Tist ein Vorlagenparameter, T&&ist eine universelle Referenz, die an alles bindet.
Angew ist nicht mehr stolz auf SO
4
+1 Auch wenn Xeos erweiterte Version aus seinem Kommentar nicht einmal erwähnt wird.
Christian Rau
12
Warum die integrierte Methode ignorieren? Lassen Sie einfach den Parameternamen weg.
Jack Aidley
26
-1, das ist lächerlich und eine unnötige Erfindung, besonders wenn Sie den Parameternamen einfach weglassen können. Ehrlich gesagt stört es mich, dass dies irgendwie 25 positive Stimmen hat.
TC1
5
@ TC1 Dies macht Ihren Code explizit darüber, was er tut und warum. Nicht verwendete Parameter oder Variablen sind ein Geruch in Ihrem Code und dies macht es explizit. Wenn Sie die Warnung deaktivieren, riecht Ihr Code mehr.
Dascandy
203

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.

Henrik
quelle
12
Und im Fall von mainkönnen Sie die Parameter ganz weglassen. Und die returnAussage im Übrigen.
Mike Seymour
4
@ MikeSeymour Ich halte es eigentlich für eine gute Praxis, die return-Anweisung wegzulassen.
Jtepe
6
@jotep Okay, ich werde beißen. Warum halten Sie es für eine gute Praxis?
Peter Wood
6
Ich fast immer auslassen main‚s return 0in einem Testfall, aber fast immer die selbsterklärend schreibt return EXIT_SUCCESSin Produktionscode. Das ist eine gute Praxis!
Leichtigkeitsrennen im Orbit
30
Dies scheint mir die beste Antwort zu sein - alles, was mit Makros oder Vorlagen zu tun hat, stellt immer noch nicht sicher, dass die Variable danach nicht mehr verwendet werden kann. Dadurch wird die Warnung stummgeschaltet und sichergestellt, dass der (unbenannte) Parameter niemals verwendet werden kann.
Alnitak
51

Es ist die <tuple>in C ++ 11 , die Verwendung der bereit beinhaltet std::ignoreObjekt, dass die uns erlauben , zu schreiben (sehr wahrscheinlich ohne Laufzeitaufwand zur Einführung):

void f(int x)
{
    std::ignore = x;
}
Tomilov Anatoliy
quelle
4
In Anbetracht dessen, dass dies in der Standardbibliothek enthalten ist und daher keine benutzerdefinierten Funktionen geschrieben werden müssen, würde ich sagen, dass dies die beste Lösung ist!
BrainStone
2
Diese Klasse ist "Zur Verwendung mit std :: tie beim Entpacken eines std :: tuple vorgesehen", nicht für diesen Anwendungsfall. Ich würde sagen, es ist eine Lösung, aber wahrscheinlich nicht die beste.
Maestro
1
Ich mag das eigentlich ignorieren .. Ofc, wenn Sie den Parameter entfernen können, entfernen Sie dies stattdessen (das wäre in allen Fällen die beste Lösung).
Gefahr89
32

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 )
{
}
Nikko
quelle
2
Früher habe ich das gemacht, aber es wird schnell zu einem Schmerz, da man mit/* ... */
Ponkadoodle
1
Es ist wahr, aber bei modernen IDEs wird, wenn Sie einen Block zum automatischen Kommentieren auswählen, am Anfang jeder Zeile ein Bündel von "//" hinzugefügt. Genau das macht Eclipse CDT. Persönlich verwende ich nur das erste Beispiel ohne Namen. (Sie können beispielsweise Namen in die Deklarationen in einer .h-Datei einfügen).
Nikko
4
@Wallacoloo Wenn ich einen großen Teil des Codes auskommentieren möchte, verwende ich #if 0 ... #endif, die verschachtelt sein dürfen und niemals mit vorhandenen / * ... * / Kommentaren in Konflikt stehen.
Dmitry Frank
1
@DmitryFrank Und die meisten Editoren und IDEs unterstützen das Ausgrauen von #if 0Blöcken als Sonderfall, auch wenn sie nicht die vollständige Präprozessor-Intelligenz unterstützen.
Thomas
30

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 mainkönnen Sie natürlich einfach die Parameter selbst weglassen:

int main()

Es gibt auch die typischen implementierungsspezifischen Tricks wie GCCs __attribute__((unused)).

Leichtigkeitsrennen im Orbit
quelle
14

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.

Mats Petersson
quelle
6
+1: In diesem Fall verursachen sie keinen Schaden und lösen ein Problem. Ich sehe keinen Grund (jenseits des lächerlichen grundlosen Mantras "benutze niemals ein Makro"), sie hier nicht einzusetzen.
Leichtigkeitsrennen im Orbit
1
Was ist der Vorteil eines Makros gegenüber dem Weglassen des Parameternamens?
Micha Wiedenmann
1
@MichaWiedenmann: Einige Parameter dürfen nur verwendet werden, wenn einige Vorverarbeitungskonstanten festgelegt sind (normalerweise in Debug).
Matthieu M.
2
@MatthieuM.: Aus MAYBE_UNUSEDdiesem 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.
Leichtigkeitsrennen im Orbit
2
Ok, das Richtige ist wahrscheinlich, es "HIDE_UNUSED_WARNING" zu nennen. Aber ich denke immer noch, dass die Verwendung eines Makros hier eine absolut gültige Idee ist. Solange das Makro so benannt ist, dass es keine Verwirrung und / oder Konflikte mit anderem Code verursacht.
Mats Petersson
13

Was hast du gegen den alten und normalen Weg?

void f(int a, int b)
{
  (void)a;
  (void)b;
  return;
}
jcayzac
quelle
Ich finde, dass einige Compiler damit zufrieden sind, aber einige Compiler sind wählerischer als andere. Die plattformübergreifende Arbeit muss in allen Zielbetriebssystemen und Compilern getestet werden, um sicherzustellen, dass alle mit der Lösung zufrieden sind.
Jesse Chisholm
12

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.

Angew ist nicht mehr stolz auf SO
quelle
12

Der Boost-Header <boost/core/ignore_unused.hpp>(Boost> = 1.56) definiert zu diesem Zweck die Funktionsvorlage boost::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.

Manlio
quelle
1
[[maybe_unused]]ist expliziter Weg, derzeit am besten.
Tomilov Anatoliy
0

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;
}
steeveeet
quelle
0

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 in Visual 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.

Andry
quelle
-1

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
6
Dies ist keine sehr gute Option, da operator=sie Nebenwirkungen haben kann.
Tamás Szelei