簡體   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