问题
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> > 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.
回答1:
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.});
Note that this constructs a vector, and then moves it into the new element using std::vector
's move copy constructor. So in this particular case it has no advantage over push_back()
. @TimKuipers 's answer shows a way to get around this issue.
回答2:
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
.
Instead you should cast the initializer list to an initializer_list
, like so:
#include <vector>
#include <initializer_list>
int main()
{
std::vector<std::vector<int>> vec;
vec.emplace_back((std::initializer_list<int>){1,2});
}
回答3:
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.
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({})
.
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
.
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.
来源:https://stackoverflow.com/questions/24550924/emplacement-of-a-vector-with-initializer-list