2017-01-16 1 views
1

Sie bitte die folgenden Ausschnitt von C++ 98-Code betrachten 0 gedruckt wird. Aber wenn bei jeder Optimierung (-O1 nach oben, -Os auch) kompiliert die -Woverflow Warnung für den else-Zweig emittiert, die nur dort für Gleitkommazahlen sein sollte:gcc Warnung "-WOverflow"

g++ test.cpp -Wall -O1 && ./a.out 
test.cpp: In instantiation of ‘T myLower() [with T = unsigned char]’: 
test.cpp:16:46: required from here 
test.cpp:9:16: warning: large integer implicitly truncated to unsigned type [-Woverflow] 
     retval = -std::numeric_limits<T>::max(); 
     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
0 

Dies scheitert auch für uint16, alle Andere Typen funktionieren so, wie sie sollten. Soweit ich das sehen kann, sollte die std::numeric_limits<uint8_t>::is_integer eine Kompilierzeitkonstante sein - warum wird der else-Zweig überhaupt kompiliert? Die Warnung ist nicht ernst oder habe ich etwas verpasst?

Ah, das passiert in gcc5 und gcc6.

Danke!

PS: Ich weiß, dass es std::numeric_limits<>::lowest() sein wird, wenn die Zukunft hier angekommen haben wird ...

+2

Warum überrascht Sie mit Code (wenn auch mit gut definierten Ergebnissen für unsigned-Typen), dass der Compiler beschwert sich über einen Überlauf-Operation an einem Überlauf Betrieb verlassen? – Peter

+0

Ich bin überrascht, weil 'is_integer' eine Kompilierzeitkonstante und wahr ist, sollte der Überlauf nicht an erster Stelle passieren? Und der Überlauf nur „passiert“ für uint8_t und uint16_t, die größeren Zahlen sind in Ordnung ... – fdgsydfgsdfgsdfg

+0

Compiler nicht zu optimieren, wenn/sonst erforderlich ist, wenn der Test eine Kompilierung konstant ist. Wenn Sie dieses Verhalten möchten, verwenden Sie ein Kompilierzeitkonstrukt (z. B. Vorlagenspezialisierung) – Peter

Antwort

1

Das Problem hier ist, dass

if (std::numeric_limits<T>::is_integer) 

schränkt nicht das, was T sein kann. Das bedeutet, dass der Branch immer kompiliert wird und eine Warnung auslösen kann, wenn die Operation einen Überlauf verursachen würde, selbst wenn die Verzweigung nie erreicht wird.

Wenn Sie C++ 17 haben, konnte man if constexpr wie

template <typename T> T myLower() { 
    if constexpr (std::numeric_limits<T>::is_integer) { 
     return std::numeric_limits<T>::min(); 
    } else { 
     return -std::numeric_limits<T>::max(); 
    } 
} 

verwenden, die nur den if Block kompilieren würde oder den else Block auf dem constexpr Zustand abhängig. Vor C++ 17 müssten Sie SFINAE verwenden, um die Funktion so zu beschränken, dass nur kompiliert wird, wenn das Template aufgelöst wird.

+0

Ah, gut. Vielen Dank. Das erledigt es: C++ 17 ist weit weg von hier ;-( – fdgsydfgsdfgsdfg

Verwandte Themen