Emplacement of a vector with initializer list

半世苍凉 提交于 2020-01-14 07:14:25

问题


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 ints 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!