In the below code we essentially assign the same value to 4 unsigned char variables in 4 different ways - but one of them using the initialization list issues a warning:
warning: narrowing conversion of '~(int)a' from 'int' to 'unsigned char' [-Wnarrowing]
#include <iostream>
#include <vector>
int main() {
unsigned char a = 0b10101010u;
unsigned char b = ~a;
unsigned char c(~a);
auto test = std::vector<unsigned char>{};
test.emplace_back(~a);
auto test2 = std::vector<unsigned char>{~a}; // THIS IS THE LINE GCC COMPLAINS ABOUT
std::cout << std::hex
<< size_t(b) << std::endl
<< size_t(c) << std::endl
<< size_t(test[0]) << std::endl
<< size_t(test2[0]) << std::endl;
return 0;
}
Can someone explain why? Is this a bug in GCC? A language limitation?
You can play with the code here :) https://godbolt.org/z/To5ezrecc
The warning is correct. In list-initialization (i.e. with braces) narrowing conversions are ill-formed, also in initialization of elements of a
std::initializer_list
. GCC is rather permissive here, since it only produces a warning instead of a hard error (as for example Clang does).In
~a
integral promotions are applied toa
. In this casea
is promoted toint
, since it can represent all values ofunsigned char
.Therefore
~a
also has typeint
and because it is also not a constant expression, the conversion required tounsigned char
for thestd::initializer_list<unsigned char>
constructor parameter is narrowing.If you really intend to do the narrowing conversion cast explicitly:
The same applies to other initialization methods using list-initialization (braces):
Both are ill-formed as well.