Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insertion to std::list<std::vector<int>> failed when using initializer list as the value?

Tags:

c++

c++11

stl

I have a C++ snippet that looks like this:

  std::list<std::vector<int>> lv;
  lv.push_back({});
  std::cout << lv.size() << std::endl; // "1"

  lv.insert(lv.end(), {});  // Oops!
  // lv.insert(lv.end(), std::vector<int>());  // OK
  std::cout << lv.size() << std::endl; // Still got "1", but why?

As you can see, when using {} to create a default std::vector<int>, the insertion didn't happen at all. While I know that there are lots of subtleties when using C++'s initializer list, I wonder what is the problem in this example?

Thanks!

like image 274
Ye Kuang Avatar asked Jun 24 '20 14:06

Ye Kuang


People also ask

Why do we use initializer list in C++?

When do we use Initializer List in C++? Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

What is uniform initialization in C++?

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.

What is std :: 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 .


2 Answers

Overload resolution for the

lv.insert(lv.end(), {});  // Oops!

call will resolve (formally, chosen as the best viable function as per [over.ics.rank]/3.1) to the following std::list<>::insert overload [extract from std::list<>::insert at cppreference, emphasis mine]:

iterator insert( const_iterator pos, std::initializer_list<T> ilist );

inserts elements from initializer list ilist before pos.

But as the initializer list is empty, there are no elements from it to be inserted.


You could likewise invoke the same insert overload with a nested list initialization within the list initialization,

lv.insert(lv.end(), {{}});  // Size is now 2.

such that the innermost list initialization will resolve to (as per [over.match.list]/1) the std::initializer_list constructor of std::vector:

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

in so inserting a single element of type std::vector<int>, specifically an an empty such vector, into the std::list<std::vector<int>> object.

like image 129
dfrib Avatar answered Oct 20 '22 07:10

dfrib


When you call push_back, the {} argument is deduced to be the element type of the list, so a single vector gets inserted into the list.

When you call insert, you are using the initializer list overload, and since the initializer list is empty, no elements get added to the list.

like image 43
cigien Avatar answered Oct 20 '22 07:10

cigien