+template <class T>
+struct hasher<T, typename std::enable_if<std::is_enum<T>::value, void>::type> {
+ size_t operator()(T key) const {
+ return Hash()(static_cast<typename std::underlying_type<T>::type>(key));
+ }
+};
+
+template <class T1, class T2>
+struct hasher<std::pair<T1, T2>> {
+ size_t operator()(const std::pair<T1, T2>& key) const {
+ return Hash()(key.first, key.second);
+ }
+};
+
+template <typename... Ts>
+struct hasher<std::tuple<Ts...>> {
+ size_t operator() (const std::tuple<Ts...>& key) const {
+ return applyTuple(Hash(), key);
+ }
+};
+
+// recursion
+template <size_t index, typename... Ts>
+struct TupleHasher {
+ size_t operator()(std::tuple<Ts...> const& key) const {
+ return hash::hash_combine(
+ TupleHasher<index - 1, Ts...>()(key),
+ std::get<index>(key));
+ }
+};
+
+// base
+template <typename... Ts>
+struct TupleHasher<0, Ts...> {
+ size_t operator()(std::tuple<Ts...> const& key) const {
+ // we could do std::hash here directly, but hash_combine hides all the
+ // ugly templating implicitly
+ return hash::hash_combine(std::get<0>(key));