C ++ 0x wird den folgenden Code und ähnlichen Code falsch formulieren, da eine sogenannte Verengungskonvertierung von a double
in a erforderlich ist int
.
int a[] = { 1.0 };
Ich frage mich, ob diese Art der Initialisierung im Code der realen Welt häufig verwendet wird. Wie viele Codes werden durch diese Änderung beschädigt? Ist es sehr aufwendig, dies in Ihrem Code zu beheben, wenn Ihr Code überhaupt betroffen ist?
Als Referenz siehe 8.5.4 / 6 von n3225
Eine Verengungskonvertierung ist eine implizite Konvertierung
- von einem Gleitkommatyp zu einem ganzzahligen Typ oder
- von long double zu double oder float oder von double zu float, außer wenn die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Konvertierung innerhalb des Wertebereichs liegt, der dargestellt werden kann (auch wenn er nicht genau dargestellt werden kann), oder
- von einem Integer-Typ oder einem Aufzählungstyp ohne Gültigkeitsbereich zu einem Fließkomma-Typ, außer wenn die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Konvertierung in den Zieltyp passt und den ursprünglichen Wert erzeugt, wenn er zurück in den ursprünglichen Typ konvertiert wird, oder
- Von einem Integer-Typ oder einem Aufzählungstyp ohne Gültigkeitsbereich zu einem Integer-Typ, der nicht alle Werte des Originaltyps darstellen kann, es sei denn, die Quelle ist ein konstanter Ausdruck und der tatsächliche Wert nach der Konvertierung passt in den Zieltyp und erzeugt den Originalwert, wenn zurück zum ursprünglichen Typ konvertiert.
c++
c++11
survey
aggregate-initialization
Johannes Schaub - litb
quelle
quelle
0
istint
sowieso schon ein .){
geschweiften Klammerinitialisierern schlecht ausgebildet}
ist und diese nur für Arrays und POD-Strukturen verwendet werden. Wenn vorhandener Code explizite Umwandlungen aufweist, zu denen er gehört, wird er nicht beschädigt.int a = 1.0;
ist immer noch gültig.Antworten:
Ich bin auf diese bahnbrechende Veränderung gestoßen, als ich GCC verwendet habe. Der Compiler hat einen Fehler für Code wie diesen gedruckt:
Glücklicherweise waren die Fehlermeldungen unkompliziert und die Korrektur war einfach:
Der Code befand sich in einer externen Bibliothek mit nur zwei Vorkommen in einer Datei. Ich denke nicht, dass die bahnbrechende Änderung viel Code beeinflussen wird. Anfänger könnten jedoch verwirrt werden .
quelle
Ich wäre überrascht und enttäuscht von mir selbst zu erfahren, dass jeder der C ++ - Codes, die ich in den letzten 12 Jahren geschrieben habe, diese Art von Problem hatte. Aber die meisten Compiler hätten die ganze Zeit über Warnungen vor "Einengungen" während der Kompilierung ausgegeben, es sei denn, ich vermisse etwas.
Verengen diese auch die Conversions?
Wenn ja, denke ich, dass sie etwas häufiger auftreten als Ihr Beispiel vom Typ Floating vom Typ Integral.
quelle
Ich wäre nicht allzu überrascht, wenn jemand von so etwas wie:
(Bei meiner Implementierung führen die letzten beiden nicht zum gleichen Ergebnis, wenn sie zurück in int / long konvertiert werden. Daher werden sie enger.)
Ich kann mich jedoch nicht erinnern, dies jemals geschrieben zu haben. Es ist nur nützlich, wenn eine Annäherung an die Grenzen für etwas nützlich ist.
Dies scheint zumindest auch vage plausibel:
aber es ist nicht ganz überzeugend, denn wenn ich weiß, dass ich genau zwei Werte habe, warum sollte ich sie dann in Arrays einfügen und nicht nur
float floatval1 = val1, floatval1 = val2;
? Was ist die Motivation, warum das kompiliert werden sollte (und funktionieren sollte, vorausgesetzt, der Genauigkeitsverlust liegt innerhalb der für das Programm akzeptablen Genauigkeit), während diesfloat asfloat[] = {val1, val2};
nicht der Fall sein sollte? So oder so initialisiere ich zwei Floats aus zwei Ints. In einem Fall sind die beiden Floats nur Mitglieder eines Aggregats.Dies erscheint besonders hart in Fällen, in denen ein nicht konstanter Ausdruck zu einer engeren Konvertierung führt, obwohl (bei einer bestimmten Implementierung) alle Werte des Quelltyps im Zieltyp darstellbar und wieder in ihre ursprünglichen Werte konvertierbar sind:
Vorausgesetzt, es gibt keinen Fehler, besteht die Lösung vermutlich immer darin, die Konvertierung explizit zu machen. Sofern Sie mit Makros nichts Seltsames tun, wird ein Array-Initialisierer meiner Meinung nach nur in der Nähe des Array-Typs oder zumindest in der Nähe des Typs angezeigt, der von einem Vorlagenparameter abhängen könnte. Eine Besetzung sollte also einfach sein, wenn sie ausführlich ist.
quelle
Ein praktisches Beispiel, dem ich begegnet bin:
Das numerische Literal ist implizit das,
double
was Werbung fördert.quelle
float
durch Schreiben0.5f
. ;)float
es sich um einen typedef- oder template-Parameter handelt (zumindest ohne Genauigkeitsverlust), aber der Punkt ist, dass der geschriebene Code mit der richtigen Semantik funktioniert und mit C ++ 11 zu einem Fehler geworden ist. Dh die Definition einer "brechenden Veränderung".Versuchen Sie, Ihren CFLAGS -Wno-Narrowing hinzuzufügen, zum Beispiel:
quelle
Eingrenzende Konvertierungsfehler interagieren schlecht mit impliziten Regeln für die Ganzzahl-Promotion.
Ich hatte einen Fehler mit dem Code, der aussah
Dies führt zu einem sich verengenden Konvertierungsfehler (der gemäß dem Standard korrekt ist). Der Grund dafür ist , dass
c
undd
implizit befördert zu werden,int
und die resultierendeint
darf nicht wieder auf char in einer Initialisiererliste verengt werden.OTOH
ist natürlich noch in Ordnung (sonst würde die Hölle losbrechen). Aber überraschenderweise sogar
ist in Ordnung und wird ohne Warnung kompiliert, wenn die Summe von c und d kleiner als CHAR_MAX ist. Ich denke immer noch, dass dies ein Fehler in C ++ 11 ist, aber die Leute dort denken anders - möglicherweise, weil es nicht einfach ist, ihn zu beheben, ohne die implizite Ganzzahlkonvertierung loszuwerden (was ein Relikt aus der Vergangenheit ist, als die Leute Code geschrieben haben wie
char a=b*c/d
und erwartet, dass es funktioniert, auch wenn (b * c)> CHAR_MAX) oder Konvertierungsfehler eingrenzen (die möglicherweise eine gute Sache sind).quelle
unsigned char x; static unsigned char const m = 0x7f; ... unsigned char r = { x & m };
<- Eingrenzung der Konvertierung in {}. "Ja wirklich?" Also konvertiert der Operator & auch implizit vorzeichenlose Zeichen in int? Nun, es ist mir egal, das Ergebnis ist garantiert immer noch ein Zeichen ohne Vorzeichen, argh.Es war in der Tat eine bahnbrechende Änderung, da die reale Erfahrung mit dieser Funktion gezeigt hat, dass gcc die Verengung in vielen Fällen zu einer Warnung aufgrund eines Fehlers gemacht hat, der auf reale Probleme bei der Portierung von C ++ 03-Codebasen auf C ++ 11 zurückzuführen ist. Siehe diesen Kommentar in einem gcc-Fehlerbericht :
quelle
Es sieht so aus, als ob GCC-4.7 keine Fehler mehr beim Eingrenzen von Conversions gibt, sondern stattdessen Warnungen.
quelle