2015-10-25 13 views
5

dieses klassische Beispiel vor:Wie kann der Parameter einer conexpr-Funktion unbenutzt markiert werden?

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept { return N; } 

Jetzt das funktioniert gut, aber es ist ein Ärgernis, gcc gibt eine Warnung aus:

warning: unused parameter ‘array’ [-Wunused-parameter] 

Bekannte Lösungen:

  • Doesn‘ t Arbeit: Wenn ich die klassische (void)arr; der Funktion hinzufüge, bekomme ich error: body of constexpr function ‘...‘ not a return-statement.
  • Unbefriedigende: Ich kann arraySize(T (&)[N]) haben, aber ich möchte das Argument aus zwei Gründen nennen:
    1. Es macht Compiler-Fehlermeldung mehr verständlich.
    2. Mehr subjektiv, ich denke, es macht den Code klarer, vor allem für diejenigen, die nicht leben und atmen diese Syntax.
  • Nicht gut: In diesem speziellen Beispiel, ich könnte auch return sizeof(array)/sizeof(array[0]);, aber dieser Ansatz ist nicht universelle Lösung, und auch ich denke, return N; ist viel schöner, auf jeden Fall auf dem Auge zu erleichtern.
  • Gut, aber nicht immer möglich: Wechseln Sie zu C++ 14 und Compiler, der es vollständig unterstützt. Dann ist constexpr Funktionskörper wie { (void)array; return N; } erlaubt.

Wie kann ich den nicht genutzten Parameter schön loszuwerden, Warnung, wenn C++ 11 mit?

+0

Ich bin nicht auf meinem Laptop, sondern einfach mit 'ArraySize (T *)' (ohne Namen für Sie tun brauche es nicht) löst nicht? Natürlich, mit dem richtigen Typ, tut mir leid, wenn ich nicht versuchen kann für Sie ... – skypjack

+0

@skypjack Wie ich es verstehe, ist ein Verweis auf Array erforderlich. Andernfalls kann der Compiler nicht automatisch 'N' geben. Deshalb wird 'arraySize (T [N])' auch nicht funktionieren (getestet, kompiliert nicht, ohne explizit 'N' als Template-Argument anzugeben, wenn die Funktion aufgerufen wird). – hyde

+1

'arraySize (T (&) [N])'? Das sollte funktionieren, aber ich bin mir nicht sicher über die Warnung, denn ich kann es nicht versuchen. Wenn es in Ordnung ist, werde ich eine Antwort geben. – skypjack

Antwort

4

Ich würde vorschlagen, die folgende (ab) Verwendung des Komma-Operator:

return (void)array, N; 
+1

Innerhalb der Grenzen der Frage mag ich das am besten, da es eigentlich nichts bewerten sollte. Wahrscheinlich klug, einen Kommentar wie '// void cast mit Komma-Operator für C++ 11 compatibility' hinzuzufügen – hyde

+0

@hyde ja, die Dokumentation der (relativ) seltsam zurückgegebenen Ausdruck mit einem Kommentar ist wahrscheinlich eine gute Idee. –

2

Die beste Lösung ist diejenige, die mit dem zweiten Punkt verboten ist, nämlich T(&)[N] zu verwenden.

Ein anderer möglicher Ansatz, wie aus dem Kommentar, ist den folgenden Rückgabewert zu verwenden:

return array ? N : N; 

ich ziemlich sicher bin, dass der Compiler wird es loszuwerden, und es wird zur Laufzeit kein Leistungsproblem sein .

+0

Wenn Sie die Warnung des Compilers unterdrücken möchten, verwenden Sie ein #pragma, um es zu unterdrücken.Einen Parameter ohne Grund zu referenzieren, um eine Compiler-Warnung zu unterdrücken, ist das Gegenteil davon, klar lesbaren Code zu schreiben. –

+1

Ich würde lieber den einzigen Typ ohne Variablennamen, das ist viel klarer als ein Pragma, aber er hat einige Einschränkungen (siehe die Frage) und dieses ist eine mögliche und portable Lösung, mehr nicht. – skypjack

4

Versuchen Sie dies. Ich benutze diese Methode manchmal

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (& /*array*/)[N]) noexcept { return N; } 
+2

hast du entweder die Frage oder die Antwort von @skypjack gelesen? –

+0

@ m.s. Ja, ich habe die Antwort nicht bis zum Ende gelesen. Ich werde meine Antwort in 10 Minuten korrigieren oder löschen. – fnc12

+1

Ich mag diese Lösung am meisten, weil sie keine unnötige Logik einführt, die den Leser wie die anderen Antworten verwirren könnte. – Sopel

1

Als @ FNC12 und @skypjack beide weisen darauf hin, die idiomatische Weise eine nicht verwendete Parameter Compiler-Warnung zum Schweigen zu bringen ist, nicht einen Namen für den Parameter zu geben.

constexpr std::size_t arraySize(T (& /*array*/)[N]) noexcept { return N; } 

Mit den /**/ Kommentare löst die Lesbarkeit Einwand. Es wird nicht der Name in einer Compiler-Nachricht behoben, aber ich würde argumentieren, dass die wahrscheinlichste Situation daraus entsteht "undeclared Identifier", die ziemlich einfach und offensichtlich zu lösen ist, sobald Sie bemerken, dass der Bezeichner kommentiert ist.

Wenn Sie wirklich tot gegen den idiomatischen Weg gesetzt sind, dann unterdrücken Sie einfach die Warnung (lokal, wenn Ihr Compiler es erlaubt).

Suppressing warnings in GCC using #pragma GCC diagnostic.

Suppressing warnings in Visual Studio using #pragma warning suppress

Ich empfehle "Dummy" Verweise auf den Code für das Hinzufügen der Compiler den Mund zu halten. Wenn Sie einen sonst nicht verwendeten Parameter ohne Grund referenzieren, um eine Compiler-Warnung zu unterdrücken, wird Ihr Code unnötigerweise komplexer, und er kann zukünftige Betreuer darüber verwirren, warum er da ist.

+1

Eigentlich, wenn man den Parameternamen in Kommentare schreibt, zeigt es zumindest * gcc * an, also hilft es auch dort (sieht natürlich etwas hässlich aus ...). Und ich bin definitiv damit einverstanden, unbenutzten Parameternamen aus der Funktion * definition * zu entfernen. Aber IMO-Deklarationen sollten sie haben, und hier sind Definition und Deklaration dieselben. – hyde

1

Das unbenannte Argument die richtige Lösung ist.

So können Sie eine Zwischenfunktion:

template <typename T> 
constexpr void avoid_warning_for_unused_parameter(T&&) noexcept{} 

und dann:

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept 
{ 
    avoid_warning_for_unused_parameter(array); 
    return N; 
} 

Für C++ 11, Sie haben etwas mehr zu hacken:

template <typename... Ts> 
constexpr auto return_first_and_avoid_warning_for_unused_parameters(T&&t, Ts&&) noexcept 
-> decltype(t) 
{ 
    return t; 
} 

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N]) noexcept 
{ 
    return return_first_and_avoid_warning_for_unused_parameters(N, array); 
} 
+0

Das ist nicht viel anders als nur den traditionellen '(void)' Cast zu verwenden, da dies * auch C++ 14 * erfordert. Ich kann den Punkt der expliziten Benennung "unbenutzter" Funktion (oder Makros) verstehen, aber ich persönlich würde das einfache alte traditionelle '(void)' Cast dem Durcheinander einer zusätzlichen Funktion vorziehen, da es ein ziemlich gut etabliertes Idiom ist. YMMV. – hyde

+1

@hyde: Laut http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/ funktioniert '(void) array' nicht für alle Compiler. – Jarod42

+0

Interessante Diskussion dort, gut zu wissen! – hyde

1

gcc stellt die unused attribute zur Verfügung, die wie folgt verwendet werden kann:

constexpr std::size_t arraySize(__attribute__((unused)) T (&array)[N]) noexcept { return N; } 
           ^^^^^^^^^^^^^^^^^^^^^^^ 

Ben Deane recently tweatted about a C++11 way diese Warnung mit Lambda-Ausdrücke zu unterdrücken, die mit dem Komma-Operator kombiniert wie folgt aussehen würde:

#define UNUSED(x) [&x]{}() 

//... 

return UNUSED(array), N; 
2

Für neue Googler:

C++ 17 fügt eine [[maybe_unused]] Attribut, das könnte wie folgt verwendet werden:

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }