Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Construct container with initializer list of iterators

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?

like image 738
Felix Glas Avatar asked Jul 31 '13 20:07

Felix Glas


People also ask

What is the Order of constructor initializer list in C++?

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.

How do you initialize a variable in a constructor?

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.

What is initializer_list in C++?

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

How do you initialize class member data in the constructor?

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.


1 Answers

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.

like image 119
Praetorian Avatar answered Oct 25 '22 19:10

Praetorian