考虑以下尝试在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
背后的逻辑的粗略理解是,对emplace
和insert
的调用应该给出相同的结果,区别在于放置既不需要移动也不需要复制。对于这些类型,使用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>){});