简体   繁体   English

使用初始化列表放置向量

[英]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?为什么 emplace_back 不能在这个位置构造元素? Or what am i doing wrong?或者我做错了什么?

Thanks for your help.谢谢你的帮助。

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});
}

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.请注意,这会构造一个向量,然后使用std::vector的移动复制构造函数将其移动到新元素中。 So in this particular case it has no advantage over push_back() .所以在这种特殊情况下,它没有超过push_back()优势。 @TimKuipers 's answer shows a way to get around this issue. @TimKuipers 的回答显示了解决此问题的方法。

There are really two issues here: the numeric type conversion and template argument deduction.这里真的有两个问题:数字类型转换和模板参数推导。

The std::vector<double> constructor is allowed to use the braced list (even of int s) for its std::vector<double>(std::initializer_list<double>) constructor.允许std::vector<double>构造函数对其std::vector<double>(std::initializer_list<double>)构造函数使用花括号列表(甚至是int std::vector<double>(std::initializer_list<double>) (Note, however, that std::initializer_list<int> does not implicitly convert to std::initializer_list<double> ) (但是请注意, std::initializer_list<int>不会隐式转换为std::initializer_list<double>

emplace_back() cannot construct the element from the brace expression because it is a template that uses perfect forwarding. emplace_back()不能从大括号表达式构造元素,因为它是一个使用完美转发的模板。 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({}) .标准禁止编译器推断{0,0}的类型,因此std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>)不会被编译对于emplace_back({})

Other answers point out that emplace_back can be compiled for an argument of type std::initializer_list<vector::value_type> , but will not deduce this type directly from a {} expression.其他答案指出, emplace_back可以std::initializer_list<vector::value_type>类型的参数编译,但不会直接从{}表达式推导出此类型。

As an alternative to casting the argument to emplace_back , you could construct the argument first.作为将参数转换为emplace_back的替代方法,您可以先构造参数。 As pointed out in Meyers' Item 30 (Effective Modern C++), auto is allowed to deduce the type of a brace expression to std::initializer_list<T> , and perfect forwarding is allowed to deduce the type of an object whose type was deduced by auto .正如 Meyers 的 Item 30 (Effective Modern C++) 所指出的,允许auto将大括号表达式的类型推导出为std::initializer_list<T> ,并且允许完美转发推导出其类型被推导的对象的类型通过auto

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

emplace_back adds an element to vec by calling std::vector<double>(std::forward<std::initializer_list<double>>(double_list)) , which triggers the std::vector<double>(std::initializer_list<double>) constructor. emplace_back通过调用std::vector<double>(std::forward<std::initializer_list<double>>(double_list))vec添加一个元素,这会触发std::vector<double>(std::initializer_list<double>)构造函数。

Reference: Section 17.8.2.5 item 5.6 indicates that the this is a non-deduced context for the purposes of template argument deduction under 17.8.2.1 item 1.参考:第 17.8.2.5 节第 5.6 项表明这是一个非推导上下文,用于 17.8.2.1 第 1 项下的模板参数推导。

Update: an earlier version of this answer erroneously implied that std::initializer_list<int> could be provided in place of std::initializer_list<double> .更新:此答案的早期版本错误地暗示可以提供std::initializer_list<int>代替std::initializer_list<double>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM