It's possible to construct a vector with an iterator range, like this:
std::vector<std::string> vec(std::istream_iterator<std::string>{std::cin},
std::istream_iterator<std::string>{});
But I can also compile and run code using C++11 uniform initialization syntax (note the bracers), like this:
std::vector<std::string> vec{std::istream_iterator<std::string>{std::cin},
std::istream_iterator<std::string>{}};
What's really going on here?
I know that a constructor taking an initializer list gets priority over other forms of construction. Shouldn't the compiler resolve to the constructor taking an initializer list containing 2 elements of std::istream_iterator
? This should be an error as a std::istream_iterator
can't be converted to the vectors value type std::string
, right?
The order of the constructor initializer list is not critical. Because C++ adheres to the order in which we lay the object in the class template. But, it is a best practice to keep the list to match with the data member layout of the class. In the below example, we have kept no order in the constructor initializer.
It begins with a colon (:), and then lists each variable to initialize along with the value for that variable separated by a comma. Note that we no longer need to do the assignments in the constructor body, since the initializer list replaces that functionality. Also note that the initializer list does not end in a semicolon.
(not to be confused with member initializer list ) An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T.
In the previous lesson, for simplicity, we initialized our class member data in the constructor using the assignment operator. For example: When the class’s constructor is executed, m_value1, m_value2, and m_value3 are created.
From §13.3.2/1 ([over.match.list])
When objects of non-aggregate class type
T
are list-initialized (8.5.4), overload resolution selects the constructor in two phases:— Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class
T
and the argument list consists of the initializer list as a single argument.— If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
T
and the argument list consists of the elements of the initializer list.
In your case the initializer list constructor is deemed non-viable (because std::istream_iterator<std::string>
is not convertible to std::string
), and the second condition applies. This results in the constructor taking 2 iterators to be selected.
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