Emplacement of a vector with initializer list
Clash 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.);
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 int
s 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.
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