Emplacement of a vector with initializer list

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Emplacement of a vector with initializer list



i have a std::vector<std::vector<double>> and would like to add some elements at the end of it so this was my trial:


std::vector<std::vector<double>>


std::vector<std::vector<double> > vec;
vec.emplace_back(0,0);



but this does not compile whereas the following will do:


std::vector<double> vector(0,0);



Why can't emplace_back construct the element at this position? Or what am i doing wrong?



Thanks for your help.




3 Answers
3



Template deduction cannot guess that your brace-enclosed initialization list should be a vector. You need to be explicit:


vec.emplace_back(std::vector<double>0.,0.);





thanks, but i have another question to this: Why does it work for the second example? Since the compiler has similar information about the type (emplace_back expects to get arguments for a constructor of std::vector<double> and so is the second example)
– m47h
Jul 3 '14 at 10:22






Because in the second example you call the constructor of vector, which can handle the initializer list directly.
– marli
Oct 25 '16 at 20:09





So effectively you're not emplacing, but just pushing an already constructed element, rather than constructing the vector in place.
– Tim Kuipers
Nov 16 '16 at 12:04





@TimKuipers Yes, indeed. This would move-copy the argument into vec.
– juanchopanza
Apr 1 at 8:20


vec



The previous answer mentioned you could get the code to compile when you construct the vector in line and emplace that.
That means, however, that you are calling the move-constructor on a temporary vector, which means you are not constructing the vector in-place, while that's the whole reason of using emplace_back rather than push_back.


emplace_back


push_back



Instead you should cast the initializer list to an initializer_list, like so:


initializer_list


#include <vector>
#include <initializer_list>

int main()

std::vector<std::vector<int>> vec;
vec.emplace_back((std::initializer_list<int>)1,2);





It would actually call the move constructor, not the copy constructor.
– Arcinde
Jul 27 '17 at 21:04





Good catch. Edited my answer.
– Tim Kuipers
Jul 29 '17 at 0:33





Why do you use the old style C-cast syntax (std::initializer_list<int>)1,2 here instead of the constructor syntax std::initializer_list<int>(1,2)?
– Peter
Dec 21 '17 at 12:42


(std::initializer_list<int>)1,2


std::initializer_list<int>(1,2)





@Peter that's a best practice question on its own. I've searched stackoverflow and found a couple of reasons, but there is no solid proof which one is the best. It seems the consensus is that both those cast styles should be avoided in favour of static_cast and the like.
– Tim Kuipers
Dec 23 '17 at 16:24



The std::vector<double> constructor is allowed to use the braced list of ints for its std::vector<double>(std::initializer_list<double>) constructor.


std::vector<double>


int


std::vector<double>(std::initializer_list<double>)



emplace_back() cannot construct the element from the brace expression because it is a template that uses perfect forwarding. The Standard forbids the compiler to deduce the type of 0,0, and so std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>) does not get compiled for emplace_back().


emplace_back()


0,0


std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>)


emplace_back()



Other answer point out that emplace_back can be compiled for an argument of type std::initializer_list<T> if it doesn't have to deduce the type directly from a expression. As an alternative to casting the argument to emplace_back, you could construct the argument first. As pointed out in Meyers' Item 30 (Effective Modern C++), auto is allowed to deduce the type of a brace expression, and perfect forwarding is allowed to deduce the type of an object whose type was deduced by auto.


emplace_back


std::initializer_list<T>



emplace_back


auto


auto


std::vector<std::vector<double> > vec;
auto int_list = 0, 0; // int_list is type std::initializer_list<int>
vec.emplace_back(int_list); // instantiates vec.emplace_back<std::initializer_list<int>>



emplace_back adds an element to vec by calling std::vector<double>(std::forward<std::initializer_list<int>>(int_list)), which triggers the std::vector<double>(std::initializer_list<double>) constructor and the elements of int_list are converted.


emplace_back


vec


std::vector<double>(std::forward<std::initializer_list<int>>(int_list))


std::vector<double>(std::initializer_list<double>)


int_list






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard