问题
I am wondering about the following warning of the clang compiler when I pass an integer
to an std::initializer_list< size_t >
:
non-constant-expression cannot be narrowed from type 'int' to 'unsigned long' in initializer list
Why can int
be casted to a size_t
but an int
not be passed to an std::initializer_list< size_t >
, i.e.
int main()
{
size_t s_t = 0;
int i = 0;
std::initializer_list<size_t> i_l = { i }; // warning
s_t = i; // no warning
return 0;
}
回答1:
You have run afoul of [dcl.init.list]/7
A narrowing conversion is an implicit conversion[...] 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.
Since i
is not a constant expression this counts as a narrowing conversion and narrowing conversions are not allowed in initializer list. If you were to use
std::initializer_list<std::size_t> i_l = { 0 };
Then it would not narrow even though 0
is an int
since the compiler knows 0
can be represented in each type.
回答2:
From [dcl.init.list]:
A narrowing conversion is an implicit conversion [...] — 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.
We are converting from int
(which allows for negative values) to size_t
(which does not), so this is a narrowing conversion. Narrowing conversions are ill-formed in list-initialization, which is what you're doing here:
std::initializer_list<size_t> i_l = { i };
However, narrowing conversions are fine elsewhere (as far as the standard is concerned):
s_t = i;
That's why the first line is ill-formed but the second is not.
回答3:
When a narrowing conversion is required while using list initialization to initialize an object, the program is ill-formed.
From the C++11 Standard (emphasis mine):
8.5.4 List-initialization
...
3 List-initialization of an object or reference of type T is defined as follows:
...
— Otherwise, if
T
is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.
The use of
int i = 0;
size_t s = {i};
falls under the same clause.
来源:https://stackoverflow.com/questions/41248340/converting-int-to-a-size-t