如何将std :: vector :: emplace_back用于vector <vector <int>&gt;?</vector <int>

时间:2013-12-05 04:46:40

标签: c++ c++11 vector

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

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

3 个答案:

答案 0 :(得分:20)

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

示例:

#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.
}

Live example

std::vector::emplace_back()是一个函数模板,其参数被推导出来。因此传递它{1, 2}将无效,因为它无法推断它。为其添加显式类型

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

会使它发挥作用。

Live example

答案 1 :(得分:1)

@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移动插入的概念中受益,通过移动构造器而不是复制来构造对象。

更新

res.push_back(move(v))起作用的reason是因为它们在C ++ 11之后overload方法std::vector::push_back(value_type&& val)。它被故意支持右值引用。

答案 2 :(得分:-1)

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

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