Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why vector<double> accepts initializer_list with integer elements?

Tags:

c++

c++11

#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.

like image 214
q0987 Avatar asked Feb 11 '17 02:02

q0987


1 Answers

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.

like image 162
Sergey Kalinichenko Avatar answered Nov 05 '22 14:11

Sergey Kalinichenko