when constructing variables using the list-initialization (like int x{ 5 };
) the standard §8.5.4 says:
If a narrowing conversion […] is required to convert any of the arguments, the program is ill-formed. (7) A narrowing conversion is an implicit conversion - (7.4) from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
So why does this compile?
char c{ 'A' };
char x{ c + c };
As a reminder, c + c
yields an int
static_assert(std::is_same_v<decltype(c + c), int>, "");
so the compiler should complain about a narrowing conversion which is certainly not a constant expression.
Interestingly, declaring x
to be an unsigned char
correctly fails to compile:
char c{ 'A' };
unsigned char x{ c + c };
C2397 conversion from 'int' to 'unsigned char' requires a narrowing conversion
As does introducing a temporary:
char c{ 'A' };
int sum{ c + c };
char x{ sum }; //C2397 conversion from 'int' to 'char' requires [...]
So why does the first version compile? I'm using Visual Studio Community 2017 Version 15.9.5 and compile it with /wall
and all warnings are errors enabled in a x64
debug build. Setting the standard C++11, C++14 and C++17 all compile.
I filed the bug report here
If you make a narrowing conversion intentionally, make your intentions explicit by using a static cast. Otherwise, this error message almost always indicates you have a bug in your code. You can fix it by making sure the objects you initialize have types that are large enough to handle the inputs.
A narrowing conversion changes a value to a data type that might not be able to hold some of the possible values. For example, a fractional value is rounded when it is converted to an integral type, and a numeric type being converted to Boolean is reduced to either True or False .
In a widening conversion, a value in a smaller variable is assigned to a larger variable with no loss of data. Because widening conversions are always safe, the compiler performs them silently and doesn't issue warnings.
Yes. You are right: the program is ill-formed.
In such a case (standard §1.4):
a conforming implementation shall issue at least one diagnostic message.
Indeed, gcc
produces a warning message. clang
directly rejects the code as a compiler error.
This specific topic has already been discussed here for gcc1.
Visual Studio
is supposed to produce a diagnostic message (I suggest you check your compilation options. Did you disable warnings? Are you compiling with C++(11/14/17)?, ...). If this is not the case, it's an implementation bug.
Update:
Visual Studio v19.20 does not produce any diagnostic message (even with /Wall
flag).
A bug report has been filled here.
1For additional information regarding gcc implementation for narrowing check here.
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