The concept of narrowing seems pretty straight-forward. However, could someone please explain why some of the code below causes "narrowing" compiler errors and others don't?
This code produces errors where expected:
constexpr int a = 255;
unsigned char b = a; // OK
unsigned char c = a + 1; // Error... expected
This code doesn't produce errors, but may be ok:
int d = 256;
unsigned char e = d; // Maybe OK because 'd' is not constexpr
This code should generate errors (unless I'm missing something):
int f = 42.0; // Maybe OK because no fractional part
int g = 42.1; // OK... should fail!!
constexpr float h = 42.7;
int i = h; // OK... should fail???
I'm using g++ 4.6.2. I searched the GCC bug database and didn't find anything related. Thanks!
To be honest, with your samples I see little wrong.
However, there are a number of cases where the compiler seems to accept 'violations' of the standard conversion rules...:
However I spotted this one in the standard:
For initialzer lists, the following is not allowed (§ 8.5.4, under 3.)
int ai[] = { 1, 2.0 }; // error narrowing
Under 6. it goes on to give a general list of examples:
[ Note: As indicated above, such conversions are not allowed at the top level in list-initializations.—end note ]
int x = 999; // x is not a constant expression
const int y = 999;
const int z = 99;
char c1 = x; // OK, though it might narrow (in this case, it does narrow)
char c2{x}; // error: might narrow
char c3{y}; // error: narrows (assuming char is 8 bits)
char c4{z}; // OK: no narrowing needed
unsigned char uc1 = {5}; // OK: no narrowing needed
unsigned char uc2 = {-1}; // error: narrows
unsigned int ui1 = {-1}; // error: narrows
signed int si1 =
{ (unsigned int)-1 }; // error: narrows
int ii = {2.0}; // error: narrows
float f1 { x }; // error: might narrow
float f2 { 7 }; // OK: 7 can be exactly represented as a float
int f(int);
int a[] = { 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level
Interestingly, g++ 4.6.1 with --std=c++0x -Wall -pedantic
catches only one of these violations:
char c3{y}; // warning: overflow in implicit constant conversion [-Woverflow]
I don't think the truncation of a float to an int is considered narrowing
.
It is just a well-defined conversion, much like
int i = 31;
i /= 4; // well defined loss of precision...
i /= 4.0; // equally well-defined conversion from floating point to int
Floating points can get converted to ints:
A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion trun- cates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.
int f = 42.0; // Equal to 42, 42 fits into int
int g = 42.1; // Equal to 42, 42 fits
constexpr float h = 42.7;
int i = h; // 42
Narrowing rules only applies to initializer lists.
unsigned char c = { 2.4 }; // narrowing
warning: narrowing conversion of ‘2.3999999999999999e+0’ from ‘double’ to ‘unsigned char’ inside { } [-Wnarrowing]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With