std::map::emplace无法解决,但插入右值有效 - 为什么?



考虑以下尝试在map中放置带有数字键的空vector

#include <map>
#include <vector>
int main () {
std::map<size_t, std::vector<size_t>> m;
m.emplace(42, {});                          // FAILS
m.insert({42, {}});                         // WORKS
}

emplace的调用无法解决:

error: no matching function for call to ‘std::map<long unsigned int, std::vector<long unsigned int> >::emplace(int, <brace-enclosed initializer list>)’
m.emplace(42, {});
^
In file included from /usr/include/c++/8/map:61,
from map_emplace.cpp:1:
/usr/include/c++/8/bits/stl_map.h:574:2: note: candidate: ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::emplace(_Args&& ...) [with _Args = {}; _Key = long unsigned int; _Tp = std::vector<long unsigned int>; _Compare = std::less<long unsigned int>; _Alloc = std::allocator<std::pair<const long unsigned int, std::vector<long unsigned int> > >; typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<std::pair<const _Key, _Tp> >::other>::iterator = std::_Rb_tree_iterator<std::pair<const long unsigned int, std::vector<long unsigned int> > >]’
emplace(_Args&&... __args)
^~~~~~~
/usr/include/c++/8/bits/stl_map.h:574:2: note:   candidate expects 0 arguments, 2 provided

尝试对向量向量做同样的事情按预期工作(编辑:使用emplace_back时不是,参见Bo Persson的答案):

std::vector<std::vector<size_t>> v;
v.emplace({});           // WORKS -- but does the wrong thing!
v.emplace_back({});      // FAILS
v.push_back({{}});       // WORKS

我对emplace背后的逻辑的粗略理解是,对emplaceinsert的调用应该给出相同的结果,区别在于放置既不需要移动也不需要复制。对于这些类型,使用insert版本没有太大危害,因为向量的内容将被移动(在这种特定情况下,向量无论如何都是空的)。不过总的来说,为什么这对std::map::emplace来说失败了?使用 GCC 8.1。

map::emplace的签名是

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

{}没有类型,无法推断。

对于emplace,您可以使用:

m.emplace(42, std::vector<std::size_t>{});

对于insert,(它的一个)签名是:

std::pair<iterator,bool> insert( const value_type& value );

所以{42, {}}被用来构造std::pair<const int, std::vector<size_t>>.

emplace的签名是不同的。

对于地图

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

VS 矢量

template< class... Args >
iterator emplace( const_iterator pos, Args&&... args );

map情况下,编译器不能从{}推断出Args,所以它失败了。

对于vector来说,这要容易得多,因为已知v.emplace({});中的第一个参数是const_iterator.因此{}可以匹配默认构造的迭代器。

编译器无法推断出{}的类型emplace因为它是一个vararg函数。强制使用类型,它将起作用:

m.emplace(42, (std::vector<size_t>){}); 

相关内容

  • 没有找到相关文章

最新更新