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.