#include <iostream>
#include <vector>
int main()
{
// case I: uniform initialization
//
int ii = 100;
// Error: cannot be narrowed from type 'int' to 'double'
// in initializer list
//
double dd{ ii };
// case II: initializer_list
//
std::vector<double> vecDouble{ 1, 2.2 }; // fine!
// case III: initializer_list
//
std::vector<int> vi = { 1, 2.3 }; // error: double to int narrowing
// case IV: intializer_list
// cannot be narrowed from type 'int' to 'double'
//
std::vector<double> vecD2{ ii, 2.2 }; // Error
}
Why there is inconsistency here where caseI doesn't accept int to double conversion but caseII allows the conversion.
Long story short, this works because converting from a constant expression int
to double
is not a narrowing conversion. In other words, this works for the same reason why the following code works:
double x { 1 };
The compiler is required to construct std::initializer_list<E>
for curly brace initialization. It knows the type of E
to be double
, because you are initializing a std::vector<double>
. This is described in details in section 8.5.4 of the C++11 standard.
Here is an example from section 8.5.4.3:
struct S { S(std::initializer_list<double>); // #1 S(const std::string&); // #2 // ... }; const S& r1 = { 1, 2, 3.0 }; // OK: invoke #1
The same section defines narrowing conversion as follows:
A narrowing conversion is an implicit conversion
- from a floating-point type to an integer type, or
- from long double to double or float, or from double to float, except where 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), or
- from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or
- 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.
The two examples with ii
fall into the third category, i.e. conversion from int
to double
when the source is not a constant expression.
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