[英]how to use std::vector::emplace_back for vector<vector<int> >?
vector<vector<int> > res;
res.emplace_back({1,2}); // change to res.push_back({1,2}); would work
This gives me error这给了我错误
main.cpp:61:25: error: no matching function for call to ‘std::vector<std::vector<int> >::emplace_back(<brace-enclosed initializer list>)’
main.cpp:61:25: note: candidate is:
In file included from /usr/include/c++/4.7/vector:70:0,
from /usr/include/c++/4.7/bits/random.h:34,
from /usr/include/c++/4.7/random:50,
from /usr/include/c++/4.7/bits/stl_algo.h:67,
from /usr/include/c++/4.7/algorithm:63,
from miscalgoc.hpp:1,
from main.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:92:7: note: void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >]
How to make this work?如何使这项工作? Also, why an allocator is needed here?
另外,为什么这里需要分配器?
The problem is that function template arguments doesn't deduce std::initializer_list
from a braced-init-list (like { 1, 2 }
). 问题是函数模板参数不会从braced-init-list(如
{ 1, 2 }
)中推导出std::initializer_list
。
Example: 例:
#include <initializer_list>
#include <type_traits>
template<typename T>
void func(T arg) {
}
int main() {
auto init_list = {1, 2}; // This works because of a special rule
static_assert(std::is_same<decltype(init_list), std::initializer_list<int>>::value, "not same");
func(std::initializer_list<int>{1, 2}); // Ok. Has explicit type.
func({1, 2}); // This doesn't because there's no rule for function
// template argument to deduce std::initializer_list
// in this form.
}
std::vector::emplace_back()
is a function template with its arguments being deduced. std::vector::emplace_back()
是一个函数模板,其参数是推导出来的。 So passing it {1, 2}
will not work because it couldn't deduce it. 因此传递它
{1, 2}
将不起作用,因为它无法推断它。 Putting an explicit type to it 为它添加一个显式类型
res.emplace_back(std::initializer_list<int>{1,2});
would make it work. 会让它发挥作用。
@Mark's answer is pretty correct. @Mark的答案非常正确。 Now let's consider a more practical case.
现在让我们考虑一个更实际的案例。 After some proper operations, you've collected some data with
vector<int>
, and feel like pushing it into vector<vector<int>>
: 经过一些正确的操作后,你已经用
vector<int>
收集了一些数据,感觉就像将它推入vector<vector<int>>
:
std::vector<std::vector<int>> res;
for (int i = 0; i < 10000; ++i) {
//
// do something
//
std::vector<int> v(10000, 0); // data acquired
res.push_back(v);
}
It's not like assigning values you already know. 这不像分配你已经知道的价值。 Utilizing
std::initializer_list
is probably no longer a solution. 使用
std::initializer_list
可能不再是一个解决方案。 In such cases, you may use std::move
(along with either emplace_back
or push_back
is acceptable) 在这种情况下,您可以使用
std::move
(可以使用emplace_back
或push_back
)
for (int i = 0; i < 10000; ++i) {
std::vector<int> v(10000, 0); // will become empty afterward
res.emplace_back(std::move(v)); // can be replaced by
// res.push_back(std::move(v));
}
The performance is more or less improved. 性能或多或少得到改善。 You can still be benefited from the concept of xvalue move-insertion, constructing objects by move-constructor rather than copying.
您仍然可以从xvalue move-insertion的概念中受益,通过move-constructor而不是复制来构造对象。
UPDATE UPDATE
The reason that res.push_back(move(v))
works is because they overload the method std::vector::push_back(value_type&& val)
after C++11. 的原因在于
res.push_back(move(v))
的工作原理是,因为它们过载的方法std::vector::push_back(value_type&& val)
C ++ 11之后。 It is made to support rvalue reference deliberately. 它是故意支持右值参考。
vector<vector > res;矢量<矢量> 水库;
res.emplace_back({1,2}); res.emplace_back({1,2});
Default type detection and conversion happens only once.默认类型检测和转换只发生一次。 It does not work twice in it's use cases.
它在它的用例中不起作用两次。 For this to work you need two deductions.
为此,您需要进行两次扣除。
{1,2} -> deduce that the container is an initializer_list of Integers. {1,2} -> 推断容器是整数的 initializer_list。
res.emplace_back( any_initializer_list_of_ints ) -> here since the member element type is known to be vector of integers AND the initializer list of integers can be used to construct a vector of integers, so the initializer_list would need to be converted to vector. res.emplace_back( any_initializer_list_of_ints ) -> 这里因为已知成员元素类型是整数向量,并且整数初始化列表可用于构造整数向量,所以需要将 initializer_list 转换为向量。
The compilers don't deduce and convert it twice at the same spot.编译器不会在同一个地方对它进行两次推导和转换。 So this will never work.
所以这永远行不通。
Take a look at the documentation for vector::emplace_back
. 看一下
vector::emplace_back
的文档 。 emplace_back
tries to create a new element in your vector, by calling the constructor for the new element with the arguments passed in. So basially, when you call emplace_back({1,2})
, it tries to pass {1,2}
in to a constructor, but since res
is a vector of vectors of ints, it's looking at vector constructors, none of which can take a brace-enclosed initializer list. emplace_back
尝试通过调用传入参数的新元素的构造函数在向量中创建一个新元素。所以基本上,当你调用emplace_back({1,2})
,它会尝试传递{1,2}
in到构造函数,但由于res
是一个向量向量的向量,它正在查看向量构造函数,其中没有一个可以采用括号封闭的初始化列表。
Also, take a look at the documentation for vector::push_back
. 另外,请查看
vector::push_back
的文档 。 When push_back
is called, it creates a default object (in this case, a vector of ints) and copies the values into it. 调用
push_back
,它会创建一个默认对象(在本例中为int的向量)并将值复制到其中。 I would guess that the reason that push_back({1,2})
works is that the brace-enclosed initializer list creates a value-type, which push_back
accepts. 我猜想
push_back({1,2})
工作原理是大括号括起来的初始化列表创建了一个值类型, push_back
接受了这个值类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.