2013-02-06 38 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的答案中)也是有用的。 –