13

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?

0

2 Answers 2

16

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.

Sign up to request clarification or add additional context in comments.

Comments

0

I ran into this and my colleagues helped me discover a solution that I thought was worth sharing:

struct RefWapperAddressHash
{
    std::size_t operator()( Object const& obj ) const
    {
        std::hash< Object const* > theHash{};
        return theHash( &obj );
    }
};

std::unordered_map< std::reference_wrapper< Object >, int, RefWrapperAddressHash > m_map;

This uses std::hash's ctor : template< class T > struct hash<T*>;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.