Search code examples
c++unordered-map

Is it possible to have std::pair as T value for unordered_map?


Here's what I was trying to do:

std::unordered_map<int, std::pair<int, int>> input;

for (int j = 0; j < n; ++j) {
    std::cin >> a;
    input.insert(a % 10, std::make_pair(a, j));
}

a is an int, BTW.

I can't use insert() function, I get an error message:

main.cpp:12:25: error: no matching function for call to 'std::unordered_map<int, std::pair<int, int> >::insert(int, std::pair<int, int>)'
   12 |             input.insert(a % 10, std::make_pair(a, j));
      |             ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/local/include/c++/12.1.0/unordered_map:47,
                 from main.cpp:1:
/usr/local/include/c++/12.1.0/bits/unordered_map.h:563:9: note: candidate: 'template<class _Pair> std::__enable_if_t<std::is_constructible<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::value_type, _Pair&&>::value, std::pair<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator, bool> > std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_Pair&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >]'
  563 |         insert(_Pair&& __x)
      |         ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:563:9: note:   template argument deduction/substitution failed:
main.cpp:12:25: note:   candidate expects 1 argument, 2 provided
   12 |             input.insert(a % 10, std::make_pair(a, j));
      |             ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:601:9: note: candidate: 'template<class _Pair> std::__enable_if_t<std::is_constructible<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::value_type, _Pair&&>::value, typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(const_iterator, _Pair&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >]'
  601 |         insert(const_iterator __hint, _Pair&& __x)
      |         ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:601:9: note:   template argument deduction/substitution failed:
main.cpp:12:28: note:   cannot convert '(a % 10)' (type 'int') to type 'std::unordered_map<int, std::pair<int, int> >::const_iterator' {aka 'std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator'}
   12 |             input.insert(a % 10, std::make_pair(a, j));
      |                          ~~^~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:616:9: note: candidate: 'template<class _InputIterator> void std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterator, _InputIterator) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >]'
  616 |         insert(_InputIterator __first, _InputIterator __last)
      |         ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:616:9: note:   template argument deduction/substitution failed:
main.cpp:12:25: note:   deduced conflicting types for parameter '_InputIterator' ('int' and 'std::pair<int, int>')
   12 |             input.insert(a % 10, std::make_pair(a, j));
      |             ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:438:7: note: candidate: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert_return_type std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(node_type&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; insert_return_type = std::_Hashtable<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::insert_return_type; node_type = std::_Hashtable<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::node_type]'
  438 |       insert(node_type&& __nh)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:438:7: note:   candidate expects 1 argument, 2 provided
/usr/local/include/c++/12.1.0/bits/unordered_map.h:443:7: note: candidate: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(const_iterator, node_type&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator; const_iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator; node_type = std::_Hashtable<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::node_type]'
  443 |       insert(const_iterator, node_type&& __nh)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:443:14: note:   no known conversion for argument 1 from 'int' to 'std::unordered_map<int, std::pair<int, int> >::const_iterator' {aka 'std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator'}
  443 |       insert(const_iterator, node_type&& __nh)
      |              ^~~~~~~~~~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:551:7: note: candidate: 'std::pair<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator, bool> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(const value_type&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator; value_type = std::pair<const int, std::pair<int, int> >]'
  551 |       insert(const value_type& __x)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:551:7: note:   candidate expects 1 argument, 2 provided
/usr/local/include/c++/12.1.0/bits/unordered_map.h:557:7: note: candidate: 'std::pair<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator, bool> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(value_type&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator; value_type = std::pair<const int, std::pair<int, int> >]'
  557 |       insert(value_type&& __x)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:557:7: note:   candidate expects 1 argument, 2 provided
/usr/local/include/c++/12.1.0/bits/unordered_map.h:590:7: note: candidate: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(const_iterator, const value_type&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator; const_iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator; value_type = std::pair<const int, std::pair<int, int> >]'
  590 |       insert(const_iterator __hint, const value_type& __x)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:590:29: note:   no known conversion for argument 1 from 'int' to 'std::unordered_map<int, std::pair<int, int> >::const_iterator' {aka 'std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator'}
  590 |       insert(const_iterator __hint, const value_type& __x)
      |              ~~~~~~~~~~~~~~~^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:596:7: note: candidate: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(const_iterator, value_type&&) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator; const_iterator = std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator; value_type = std::pair<const int, std::pair<int, int> >]'
  596 |       insert(const_iterator __hint, value_type&& __x)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:596:29: note:   no known conversion for argument 1 from 'int' to 'std::unordered_map<int, std::pair<int, int> >::const_iterator' {aka 'std::__detail::_Insert_base<int, std::pair<const int, std::pair<int, int> >, std::allocator<std::pair<const int, std::pair<int, int> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::const_iterator'}
  596 |       insert(const_iterator __hint, value_type&& __x)
      |              ~~~~~~~~~~~~~~~^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:627:7: note: candidate: 'void std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(std::initializer_list<typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::value_type>) [with _Key = int; _Tp = std::pair<int, int>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<int, int> > >; typename std::_Hashtable<_Key, std::pair<const _Key, _Val>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::__is_nothrow_invocable<const _Hash&, const _Key&> > >::value, false, true> >::value_type = std::pair<const int, std::pair<int, int> >]'
  627 |       insert(initializer_list<value_type> __l)
      |       ^~~~~~
/usr/local/include/c++/12.1.0/bits/unordered_map.h:627:7: note:   candidate expects 1 argument, 2 provided

https://coliru.stacked-crooked.com/a/fee75ea0e9c957b6


Solution

  • std::unordered_map::insert provides several overloads, but none that take the key and value as separate elements. This is for consistency with other collections, for which insert generally takes a single element to insert. An std::unordered_map, in the context of the C++ collections API, is thought of as an unordered collection of std::pair<K, V> elements, where K and V are the key and value type, respectively. That is, you're looking for one of the first two overloads.

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

    (Note: std::unordered_map::value_type is defined to be std::pair<const Key, T>.)

    So what you're looking for is

    input.insert(std::make_pair(a % 10, std::make_pair(a, j)));
    

    If you think that's not very readable, you can always assign to operator[], which will default construct a value if there isn't already one at the position. I would not do this if T fails to be default constructible or if default constructing T is expensive, but for std::pair<int, int>, it's dirt cheap, and I think the improvement to readability speaks for itself.

    input[a % 10] = std::make_pair(a, j);