std::map::emplace не удается разрешить, но вставка rvalue работает - почему?
Рассмотрим следующую попытку вставить пустой vector
с числовым ключом в map
:
#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
ср. Ответ Бо Перссона):
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
должен давать тот же результат, с той разницей, что emplace не требует ни перемещения, ни копирования. Для этих типов нет большого вреда в использовании insert
версия, так как содержимое вектора будет перемещено (и в этом конкретном случае вектор пуст, в любом случае). В общем, почему это не удается для std::map::emplace
? Использование GCC 8.1.
3 ответа
Подпись 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 );
против вектора
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>){});