Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an object reference as a key in std::unordered_map

I'd like to know if it is possible to use an object reference as a key in an unordered_map container in C++.

#include <unordered_map>

class Object {
    int value;
};

struct object_hash {
  inline size_t operator()(const Object& o) const { return 0; }
};

std::unordered_map<Object&, int, object_hash> map;

When trying to compile this simple snippet, I got some errors about methods redefinition:

Using clang with libc++

/usr/include/c++/v1/unordered_map:352:12: error: class member cannot be redeclared

size_t operator()(const _Cp& __x) const

Using gcc 4.6 with libstdc++

/usr/include/c++/4.6/bits/hashtable_policy.h:556:5: error: ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator [with _Key = Object&, _Pair = std::pair, _Hashtable = std::_Hashtable, std::allocator >, std::_Select1st >, std::equal_to, object_hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’ cannot be overloaded

/usr/include/c++/4.6/bits/hashtable_policy.h:537:5: error: with ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](const _Key&) [with _Key = Object&, _Pair = std::pair, _Hashtable = std::_Hashtable, std::allocator >, std::_Select1st >, std::equal_to, object_hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’

If I use an old gnu hash_map instead (__gnu_cxx::hash_map), I don't have this problem.

Is this some limitation imposed by the new standard, and if so, why?

Is there a way to workaround this limitation?

like image 469
Jean-Daniel Dupas Avatar asked May 22 '12 14:05

Jean-Daniel Dupas


People also ask

Can I use a pair as a key for unordered map?

Unordered Map does not contain a hash function for a pair like it has for int, string, etc, So if we want to hash a pair then we have to explicitly provide it with a hash function that can hash a pair. unordered_map can takes upto 5 arguments: Key : Type of key values.

What does unordered_map return if key not found?

Note that while unordered_map::at() will throw if the key is not found, unordered_map::find() returns an invalid iterator ( unordered_map::end() ) - so you can avoid handling exceptions this way.

How do you pass an unordered map in a function?

Just replace the int with something like unordered_map<int, int> . You're going to want to pass it with a const reference if you don't need to modify it. Don't use the const if you want to modify the original object that was used to call the function. Save this answer.

How are elements stored in unordered_map?

unordered_map is an associated container that stores elements formed by the combination of a key value and a mapped value. The key value is used to uniquely identify the element and the mapped value is the content associated with the key. Both key and value can be of any type predefined or user-defined.


1 Answers

The new standard defines std:reference_wrapper<T> to work around this limitation.

It is implicitly convertible to a T& so that it is transparent, and like references guarantee there is no null state, however unlike references it can be re-seated.

More information in Using std::reference_wrapper as key in std::map.

like image 147
Matthieu M. Avatar answered Sep 28 '22 04:09

Matthieu M.