intrigued_66
intrigued_66

Reputation: 17248

Using Boost strong typedef with unordered_map

I am using a Boost strong typedef to strong-type uint64_t:

BOOST_STRONG_TYPEDEF(uint64_t, MyInt)

and an std::unordered_map using this:

std::unordered_map<MyInt, int> umap;

Unfortunately I get a lot of compiler errors (can't paste here as they're on another machine):

error: static assertion failed: hash function must be invocable with an argument of key type
.static_assert(__is_invocable<const _H1&, const _Key&>)

error: use of deleted function 'std::__detail::_Hashtable_ebo_helper

_Hashtable() = default;

(+ a lot more I cannot type)

Using a Boost strong type as the key definitely causes the problem because if I remove the unordered_map I get no compiler errors.

Upvotes: 1

Views: 300

Answers (1)

Fareanor
Fareanor

Reputation: 6805

From the boost documentation about BOOST_STRONG_TYPEDEF, it is clearly mentioned that it defines a new type wrapping the target inner type (it is not a simple alias).

Knowing that, there is no defined std::hash<MyInt> specialization available (required by std::unordered_map<MyInt, int>) since MyInt is now a distinct type from uint64_t.

You just need to provide one and it should work as expected.

For instance:

namespace std
{
    template <>
    struct hash<MyInt>
    {
        size_t operator()(const MyInt & m) const
        {
            return hash<uint64_t>{}(m);
        }
    };
}

Edit:

As pointed out in comments, you could also directly pass the proper std::hash<> specialization to use from the std::unordered_map<> instantiation as the third template parameter since MyInt is implicitly convertible to uint64_t (as mentioned in the boost documentation as well).

It would then become:

std::unordered_map<MyInt, int, std::hash<uint64_t>> umap;

No need to define your own std::hash<MyInt> specialization anymore.

Upvotes: 4

Related Questions