2013-02-06 37 views
15
爲什麼在標準同時存在

超載的std :: unordered_map的::插入

std::unordered_map::insert(const value_type&) 

template<class P> std::unordered_map::insert(P&&) 

你教教我?

我認爲insert(P&&)可以作爲insert(const value_type&)

+3

沉默........從TR1 –

+0

遺產可能。也許他們想要安全,而不是刪除功能,只添加它們。也許他們在使用TR1的現有代碼可能產生的影響時並不確定。 –

+0

我試圖構建一個[程序](http://liveworkspace.org/code/4y16As$46),如果你刪除了'insert(const value_type&)',並且失敗,那麼這個程序無法編譯。任何人都有想法? – Yakk

回答

7

這些重載

auto std::unordered_map::insert(const value_type&) -> ... 

template<class P> 
auto std::unordered_map::insert(P&&) -> ... 

雙方都有各自的優點和既不完全可以取代其他。似乎喜歡,因爲P第二個特例第一個可能被推斷爲const value_type&。關於第二次重載的好處是可以避免不必要的副本。例如,在這種情況下:

mymap.insert(make_pair(7,"seven")); 

這裏,make_pair的結果實際上是一個pair<int, const char*>value_type可能是pair<const int, string>。因此,而不是創建一個臨時value_type對象和複製它放入容器中,我們必須通過轉換參數和/或移動其成員直接創建value_type對象到地圖的機會。

。另一方面,這將是很好,如果這工作,以及:

mymap.insert({7,"seven"}); 

但這個名單其實不是一個表情!因此,編譯器無法推導出第二次過載的P.第一次過載仍然可行,因爲您可以使用這樣的列表複製初始化pair<const int,string>參數。

+0

非常感謝!由於我還不能完全理解爲什麼'insert(const value_type&)'對於insert({7,「seven」})'是可行的,所以我更多地閱讀了標準。再次感謝!! –

+0

我發佈了一個[相關問題](http://stackoverflow.com/questions/14757809/overload-of-stdunordered-mapinsert-reloaded)。 –

2

不同之處在於所用參考的類型。第一個

std::unordered_map::insert(const value_type&) 

使用現在在(C++ 11)中稱爲左值引用的引用(C++ 03)。這需要是const。 C++ 11引入了右值引用P&&,它們不需要是const。 爲了同時允許,提供了兩個插入函數。

請在StackOverflow上看到這個優秀的答案wrt rvalue在C++ 11中的引用,我希望這有助於回答你的問題。

What does T&& (double ampersand) mean in C++11?

正如你所說的,它是可以使用右值過載,只是傳遞一個常量左值裁判,但 - 看到http://msdn.microsoft.com/en-us/library/dd293668.aspx

By overloading a function to take a const lvalue reference or an rvalue reference, you can write code that distinguishes between non-modifiable objects (lvalues) and modifiable temporary values (rvalues).

-Hannes本文

+0

糟糕,遺憾的鏈路的重複。當沒有答案時,我開始寫我的答案,但被打斷了。 –

+1

除了閱讀兩篇鏈接文章的第一部分(關於移動語義)之外,還應該閱讀關於完美轉發和參考摺疊規則的第二部分。由於'insert'將複製或移動傳入的參數,所以沒有理由在插入本身之間區分左值和右值,'value_type'的構造函數將爲您執行此操作。 –

4

n1858中增加了模板通用參考超載,其中基本原理(對於map,但明確適用於multimap):

Two of the insert signatures are new. They have been added to allow moving from rvalue types other than value_type , which are convertible to value_type . When P instantiates as an lvalue, the argument is copied into the map , else it is moved into the map (const qualifiers permitting).

(其他insert簽名稱作是插入與 - 提示。)

我們也參考了理deque(再次,明確了其他容器中引用):

All member functions which insert (or append, prepend, etc.) a single value_type into the container are overloaded with a member function that accepts that value_type by rvalue reference so that single value_type's can be moved into the container. This not only makes working with heavy weight types much more efficient, it also allows one to insert movable but non-copyable types into the container.

很明顯,這些變化主要被認爲是補充;當時沒有考慮到模板過載可能完全取代原始(C++ 03)insert。這可以通過參照前面n1771,它提供了一些動機爲模板過載,採取了不同的方法中可以看出:(CCCopyConstructible的縮寫)

Note below that for map and multimap that there are two new insert overloads, both taking a pair with a non-const key_type. One can not move from a const key_type, and therefore to be able to move a key_type into the (multi)map, a pair must be used. There are overloads for both a const lvalue pair, and a non-const rvalue pair so that lvalue pair's will not be moved from.

pair<iterator, bool> insert(const value_type& x); // CC 
pair<iterator, bool> insert(const pair<key_type,mapped_type>& x); // CC 
pair<iterator, bool> insert(pair<key_type,mapped_type>&& x); 

似乎然後,該template過載被添加到mapmultimap沒有意識到他們使const value_type &過載冗餘。您可能會考慮提交缺陷報告以刪除冗餘過載。

+0

謝謝你的回答。然而,我認爲,即使發生複製,'insert({...})'(在sellibitze的答案中)也是有用的。 –