Skip to content

Commit

Permalink
Add hashable base for std::hash of strong typedefs (foonathan#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohelEGP authored and foonathan committed Mar 23, 2018
1 parent 4fc976c commit a306972
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
15 changes: 14 additions & 1 deletion example/strong_typedef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <iostream>
#include <string>
#include <unordered_set>

#include <type_safe/strong_typedef.hpp>

Expand Down Expand Up @@ -55,12 +56,24 @@ std::ostream& operator<<(std::ostream& out, const distance& d)
return out << static_cast<unsigned>(d) << " distance";
}

namespace std
{
// we want to use it with the std::unordered_* containers
template <>
struct hash<::distance> : type_safe::hashable<::distance>
{
};

} // namespace std

int main()
{
distance d(4);
// int val = d; // error
// d += 3; // error
d += distance(3); // works

std::cout << d << '\n';
std::unordered_set<distance> set{d};

std::cout << *set.find(d) << '\n';
}
19 changes: 17 additions & 2 deletions include/type_safe/strong_typedef.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ namespace type_safe

/// Some operations for [ts::strong_typedef]().
///
/// They all generate operators forwarding to the underlying type,
/// inherit from then in the typedef definition.
/// They all generate operators forwarding to the underlying type.
/// Inherit from them in the typedef definition.
namespace strong_typedef_op
{
/// \exclude
Expand Down Expand Up @@ -729,6 +729,21 @@ namespace type_safe
#undef TYPE_SAFE_DETAIL_MAKE_OP_COMPOUND
#undef TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP
} // namespace strong_typedef_op

/// Inherit from it in the `std::hash<StrongTypedef>` specialization to make
/// it hashable like the underlying type. See example/strong_typedef.cpp.
template <class StrongTypedef>
struct hashable
{
using underlying_type = type_safe::underlying_type<StrongTypedef>;
using underlying_hash = std::hash<underlying_type>;

std::size_t operator()(const StrongTypedef& lhs) const
noexcept(noexcept(underlying_hash{}(std::declval<underlying_type>())))
{
return underlying_hash{}(static_cast<const underlying_type&>(lhs));
}
};
} // namespace type_safe

#endif // TYPE_SAFE_STRONG_TYPEDEF_HPP_INCLUDED

0 comments on commit a306972

Please sign in to comment.