2010-06-29 6 views
5

ich ein Problem habe, die ich bin sicher, einfach zu beheben, aber ich bin ratlos ...Fixing „Vergleich ist immer falsch ...“ Warnung in GCC

ich eine Vorlage haben, die (immer falsch ist aufgrund der begrenzten Reichweite von DatentypVergleich), wenn dieser Code kompiliert wird für einen Typ ohne Vorzeichen

T value  = d; 
if (std::numeric_limits<T>::is_signed) 
{ 
    if (value < 0) 
    { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

Nun denn offensichtlichen Gründen ist GCC mir eine Warnung zu geben: führt den folgenden Code ein. Ich verstehe voll und ganz die Gründe dafür und ich habe die numeric_limits-Prüfung durchgeführt, um zu sehen, ob ich den Compiler dazu bringen könnte, den Mund zu halten (es funktionierte für MSVC). Ach, unter GCC bekomme ich die Warnung. Gibt es eine Möglichkeit, diese Warnung zu beheben (kurz vor dem Deaktivieren der Warnung, die ich nicht einmal weiß, wenn Sie mit GCC tun können)? Der Code wird sowieso nie aufgerufen und ich nehme an, der Optimierer wird es auch kompilieren, aber ich werde die Warnung nicht los.

Kann mir jemand eine Lösung geben?

Prost!

+2

Dies ist sehr böse, wenn "Int" 16 Bit ist. Wenn "value" ein long ist, schneidet "value = - (signed/* int * /) value" größere Werte ab. Multiplizieren Sie stattdessen mit -1, und lassen Sie es vom Optimierer herausfinden. – MSalters

Antwort

5

Einfachere Lösung:

template <typename T> inline bool isNegative(T value) { 
    return std::numeric_limits<T>::is_signed && value < 0; // Doesn't trigger warning. 
} 

T value  = d; 
if (isNegative(value)) // Doesn't trigger warning either. 
{ 
    *this += _T("-"); 
    value = -1 * value; 
} 
+0

Leider, während das die Warnung auf gcc behebt, führt es eine neue Warnung auf MSVC ein, weil 'isNegative' niemals den Parameter' value' verwendet, wenn er mit einem vorzeichenlosen Typ 'aufgerufen wird (Warnung C4100: 'Wert': nicht referenzierter formaler Parameter) '. Es ist schwierig, jeden Compiler zufriedenzustellen - es wäre vielleicht besser, die Warnung zu deaktivieren, als Code zu schreiben, der überall sauber kompiliert wird. –

+0

Um darauf zu erweitern; Ich denke, jede Lösung, die Sie finden werden, wird entweder eine Compiler-Warnung verursachen oder eine verschachtelte Logik enthalten, die schwieriger zu warten ist. –

+0

Ich nehme an, die 'std :: numeric_limits :: is_signed' in einer Funktionsschablone zu verpacken, könnte die Warnung entfernen:' template bool is_signed (const T &) {return std :: numeric_limits :: is_signed;} '- allerdings wenn es tut so, es (es als Version von MSalters) es __at kostet Kosten einer Kompilierungszeitprüfung in einem Laufzeitcheck__. Am Ende würde ich wahrscheinlich die Warnung in VC ('#pragma warn (push: 4100)', IIRC) direkt vor der beanstandeten Zeile abschalten und sie wieder einschalten ('#pragma warn (pop)') danach. – sbi

3

Kann mir jemand eine Lösung geben?

Nichts revolutionär, aber ich mache das normalerweise durch Überladung. Etwas in diese Richtung:

//Beware, brain-compiled code ahead! 
template< bool B > 
struct Bool { const static bool result = B; } 

template< typename T > 
void do_it(T& , Bool<false> /*is_signed*/) 
{ 
    // nothing to do for unsigned types 
} 

template< typename T > 
void do_it(T& value, Bool<true> /*is_signed*/) 
{ 
    if (value < 0) { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

template< typename T > 
void do_something(T& value) 
{ 
    do_it(value, Bool<std::numeric_limits<T>::is_signed>()); 
} 

Wenn Sie Klassen-Templates anstelle von Funktionsschablonen verwenden können, können Sie Spezialisierung statt Überlastung verwenden. (Es gibt keine Funktion Schablonen-Teil Spezialisierung, die Funktion ein bisschen mehr einen Streit Vorlagen spezialisiert macht.)

+0

Ein bisschen zu kompliziert - Einführung einer Kompilierzeit Wrapper um Bool und einen zusätzlichen Parameter für den Anruf? Außerdem muss "Wert" von einer nichtkonstanten Referenz übergeben werden, da sein Wert geändert wird. Da "th" verwendet wird, ist "T" wahrscheinlich ein Vorlagenparameter der Klasse, nicht die Funktion. –

+0

Wenn ich kommentiert habe, würde Ihre Lösung nicht kompiliert werden, weil Sie eine Konstante const für einen mutierten Wert verwenden. Es tut mir leid, wenn du das so interpretierst, als ob ich mit dir "verärgert" bin. Sie könnten auch bemerken, dass ich Ihre Antwort nicht abgestimmt habe. Die Änderung, die ich an meinem Kommentar vorgenommen habe, war, den letzten Satz hinzuzufügen. –

+0

@Joe: Dann muss ich deinen Kommentar falsch gelesen haben und ich entschuldige mich für meine Antwort. Ich habe meinen Kommentar entfernt. (Ihr Kommentar stimmte mit dem überein, was sich später herausstellte, BTW, das ich zuerst als Down-Vote gewählt hatte.) Jedenfalls, was den 'Bool <>' -Typ betrifft: Ich würde nicht träumen zu programmieren C++ ohne das in meiner Toolbox. Es ist immer da und ich muss es nur greifen, wenn ich es brauche.':)' – sbi

2

Sie Ihre Funktion wie diese spezialisieren können:

template <bool S> 
void manipulate_sign(T&) {} 

template <> 
void manipulate_sign<true>(T& value) { 
    if (value < 0) 
    { 
    *this += _T("-"); 
    value = -(signed)value; 
    } 
} 

//then call like this: 
manipulate_sign<std::numeric_limits<T>::is_signed>(); 

einfach die Warnung zu deaktivieren könnte allerdings besser sein.

+1

Ich würde diese Funktion definitiv umpacken, so dass der Benutzer 'numeric_limits' nicht selbst verwenden muss -' T' ist die ganze Information, die die Funktion benötigt :) –

3

Siehe https://stackoverflow.com/a/8658004/274937 für die reale Lösung, die -Wtype-Grenzen Warnungen von Fall zu Fall erlaubt es unterdrückt wird. Kurz gesagt, wickeln Sie einfach jeden Vergleich, der die Warnung generiert, in eine Dummy-Funktion.

Verwandte Themen