Consider the following attempt to emplace an empty vector
with a numeric key in a map
:
#include <map>
#include <vector>
int main () {
std::map<size_t, std::vector<size_t>> m;
m.emplace(42, {}); // FAILS
m.insert({42, {}}); // WORKS
}
The call to emplace
fails to resolve:
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
Attempting to do the same thing with a vector of vectors works as expected (EDIT: not when using emplace_back
, cf. Bo Persson's answer):
std::vector<std::vector<size_t>> v;
v.emplace({}); // WORKS -- but does the wrong thing!
v.emplace_back({}); // FAILS
v.push_back({{}}); // WORKS
My rough understanding of the logic behind emplace
is that the calls to emplace
and insert
should give the same result, the difference being that emplace requires neither move nor copy. For these types, there is not much harm in using the insert
version, since the contents of the vector would be moved (and in this specific case, the vector is empty, anyway). In general though, why does this fail for std::map::emplace
? Using GCC 8.1.
signature of map::emplace
is
template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );
and {}
has no type and cannot be deduced.
You might use, for emplace
:
m.emplace(42, std::vector<std::size_t>{});
For insert
, (one of its) signature is:
std::pair<iterator,bool> insert( const value_type& value );
so {42, {}}
is used to construct std::pair<const int, std::vector<size_t>>
.