繁体   English   中英

如何将 std::vector::emplace_back 用于向量<vector<int> >? </vector<int>

[英]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

这给了我错误

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

如何使这项工作? 另外,为什么这里需要分配器?

问题是函数模板参数不会从braced-init-list(如{ 1, 2 } )中推导出std::initializer_list

例:

#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()是一个函数模板,其参数是推导出来的。 因此传递它{1, 2}将不起作用,因为它无法推断它。 为它添加一个显式类型

res.emplace_back(std::initializer_list<int>{1,2});

会让它发挥作用。

实例

@Mark的答案非常正确。 现在让我们考虑一个更实际的案例。 经过一些正确的操作后,你已经用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);
}

这不像分配你已经知道的价值。 使用std::initializer_list可能不再是一个解决方案。 在这种情况下,您可以使用std::move (可以使用emplace_backpush_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));
}

性能或多或少得到改善。 您仍然可以从xvalue move-insertion的概念中受益,通过move-constructor而不是复制来构造对象。

UPDATE

原因在于res.push_back(move(v))的工作原理是,因为它们过载的方法std::vector::push_back(value_type&& val) C ++ 11之后。 它是故意支持右值参考。

矢量<矢量> 水库;

res.emplace_back({1,2});

默认类型检测和转换只发生一次。 它在它的用例中不起作用两次。 为此,您需要进行两次扣除。

  1. {1,2} -> 推断容器是整数的 initializer_list。

  2. res.emplace_back( any_initializer_list_of_ints ) -> 这里因为已知成员元素类型是整数向量,并且整数初始化列表可用于构造整数向量,所以需要将 initializer_list 转换为向量。

编译器不会在同一个地方对它进行两次推导和转换。 所以这永远行不通。

看一下vector::emplace_back文档 emplace_back尝试通过调用传入参数的新元素的构造函数在向量中创建一个新元素。所以基本上,当你调用emplace_back({1,2}) ,它会尝试传递{1,2} in到构造函数,但由于res是一个向量向量的向量,它正在查看向量构造函数,其中没有一个可以采用括号封闭的初始化列表。

另外,请查看vector::push_back文档 调用push_back ,它会创建一个默认对象(在本例中为int的向量)并将值复制到其中。 我猜想push_back({1,2})工作原理是大括号括起来的初始化列表创建了一个值类型, push_back接受了这个值类型。

暂无
暂无

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

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