Home > Software engineering >  Conversion from initializer_list<const char*> to initializer_list<string> in vector cons
Conversion from initializer_list<const char*> to initializer_list<string> in vector cons

Time:09-10

std::vector‘s initializer list constructor has the form

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

What makes an initialization like std::vector<string> vec{ “foo”, “bar” }; possible? Why does the constructor accept an std::initializer_list<const char*>, even though the std::vectors‘s T is std::string? Where and how does the conversion from std::initializer_list<const char*>to std::initializer_list<string> happen?

CodePudding user response:

I think you should refer to this section of the C 17 Standard (11.6.4 List-initialization)

5 An object of type std::initializer_list is constructed from an initializer list as if the implementation generated and materialized (7.4) a prvalue of type “array of N const E”, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible (Clause 14) in the context of the initializer list. — end note ] If a narrowing conversion is required to initialize any of the elements, the program is ill-formed. [ Example:

struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };

The initialization will be implemented in a way roughly equivalent to this:

const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a 3));

assuming that the implementation can construct an initializer_list object with a pair of pointers. — end example ]

Pay attention to that there is the conversion constructor for the class std::basic_string

basic_string(const charT* s, const Allocator& a = Allocator());

So in this declaration

std::vector<string> vec{ “foo”, “bar” };

at first an object of the type std::initializer_list<std::string> is constructed from the initializer list and then is used as an initializer for the vector of the type std::vector<std::string>.

If instead you will write

std::initializer_list<const char *> lst = { "foo", "bar" };
std::vector<std::string> vec( lst );

then the compiler will issue an error because there is no implicit conversion from the type std::initializer_list<const char *> to the type std::initializer_list<std::string>.

That is the compiler determines whether it can build std::initializer_list from a braced initializer list to call the initializer-list constructor.

  • Related