Two things every C++ tutorial mentions early on:
int narrow{1.7}; // error: narrowing conversion of '1.7e+0' from 'double' to 'int'
float some_float{1.7f};
However, when working with the g++ compiler on Windows, I've discovered something odd -
float narrow{1.7}; // still a float despite no f postfix
double not_narrow{1.7}; // actually a double
This code compiles without any errors, and sizeof(narrow)
returns 4, where sizeof(not_narrow)
returns 8, as expected.
Hovering over 1.7, VSCode identifies it as a double literal ~=1.699999999999999956, but float has then narrowed it to ~=1.700000048.
I thought it might be simply that 1.7 is both valid as a float and a double, so I tried
float narrow{1.699999999999999956};
but this produces an identical result.
Why doesn't braced initialization throw an error (warning, diagnostic message, anything) here for narrowing a double literal to a float? Is this g++ specific, or a quirk of C++ in general? I'd love to understand better.
A conversion from a floating-point type to a shorter floating-point type is not a narrowing conversion if "the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly)" (C++20 [dcl.init.list]/7.2).
If you think about it, double{1.7}
and float{1.7}
are most likely both inexact. But if you write the latter, it's reasonable to assume that you mean it, and there's not much to be gained from prohibiting this.