How to Implement Custom Hash Functions in Abseil C++: A Complete Guide

To implement custom hash functions in Abseil, define a templated free function AbslHashValue that combines your type's fields using H::combine() and returns the updated hash state.

The Abseil C++ library provides a high-performance hashing framework centered around absl::Hash and the HashState machinery. To make your custom types compatible with Abseil's hash containers like absl::flat_hash_map, you must implement the AbslHashValue customization point. This approach allows you to integrate user-defined types without modifying the library itself, ensuring optimal performance and compatibility across the Abseil ecosystem.

The AbslHashValue Customization Point

The Abseil hashing framework uses AbslHashValue as its primary extension mechanism. This templated free function allows you to define how your type's fields contribute to the hash computation.

The algorithm follows three conceptual steps:

  1. Receive a hash state — The framework passes an H object (typically absl::HashState) into your function.
  2. Combine each member — Call H::combine(std::move(state), member...) for every field you want to include.
  3. Return the updated state — The returned H is then used by absl::Hash to produce the final size_t value.

Because AbslHashValue is a template, it works with any hash-state implementation, including internal types like absl::HashStateImpl, ensuring forward compatibility with the library's internal and external hash utilities.

Step-by-Step Implementation

Basic Struct Example

For a simple struct with primitive fields, implement AbslHashValue as a free function in the same namespace as your type:

#include "absl/hash/hash.h"

struct Point {
  int x;
  int y;
};

template <typename H>
H AbslHashValue(H h, const Point& p) {
  return H::combine(std::move(h), p.x, p.y);
}

This enables Point to work immediately with absl::flat_hash_set<Point> and absl::flat_hash_map<Point, T>.

Complex Types with Containers

When hashing classes containing standard library containers, AbslHashValue handles the recursive combination automatically:

#include <string>
#include <vector>
#include "absl/hash/hash.h"

class Person {
 public:
  std::string name;
  std::vector<int> favorite_numbers;
};

template <typename H>
H AbslHashValue(H h, const Person& p) {
  h = H::combine(std::move(h), p.name);
  for (int n : p.favorite_numbers) {
    h = H::combine(std::move(h), n);
  }
  return h;
}

The H::combine method automatically dispatches to existing hash implementations for std::string and int, handling the variable-length vector iteration manually.

Bridging std::hash and absl::Hash

You can make your type compatible with both the C++ standard library and Abseil by forwarding std::hash to absl::Hash:

namespace std {
template <>
struct hash<Point> {
  size_t operator()(const Point& p) const noexcept {
    return absl::Hash<Point>{}(p);
  }
};
}

This pattern allows seamless use in both std::unordered_map and absl::flat_hash_map.

Internal Mechanics and Source Files

According to the abseil-cpp source code, the hashing infrastructure resides in specific locations:

  • absl/hash/hash.h: Defines the public absl::Hash class template and declares the AbslHashValue customization point.
  • absl/hash/internal/hash.h: Contains the low-level HashState and HashStateImpl classes that implement the actual mixing logic.
  • absl/hash/internal/city.h: Houses CityHash-derived mixing primitives used by the default hash state to distribute entropy.

When absl::Hash<T>{}(value) is invoked, the library calls your AbslHashValue implementation, which feeds data into the cryptographic-strength mixing algorithms defined in the internal headers. Your custom function integrates directly with these components without requiring access to private implementation details.

Summary

  • Implement custom hash functions in Abseil by defining a templated AbslHashValue function for your type.
  • Use H::combine() to fold each field into the hash state, returning the final state object.
  • Place AbslHashValue in the same namespace as your type to ensure Argument-Dependent Lookup (ADL) works correctly.
  • Forward std::hash specializations to absl::Hash for dual compatibility with standard and Abseil containers.
  • Reference implementation details in absl/hash/hash.h and absl/hash/internal/hash.h for advanced customization.

Frequently Asked Questions

Why should I use AbslHashValue instead of specializing std::hash?

Using AbslHashValue provides better integration with Abseil's entire hashing ecosystem, including absl::flat_hash_map and absl::node_hash_set. It also allows you to maintain a single definition that works for both absl::Hash and std::hash by forwarding the latter to the former, ensuring consistent hashing behavior across all containers while respecting the library's mixing and strength guarantees.

Can I use AbslHashValue with Abseil's flat_hash_map containers?

Yes. Once you define AbslHashValue for your type, it becomes immediately usable as a key in absl::flat_hash_map, absl::flat_hash_set, absl::node_hash_map, and absl::node_hash_set. The containers automatically detect and use your custom hash implementation through the absl::Hash mechanism.

How does H::combine handle different field types?

The H::combine method uses overload resolution to recursively hash each argument. It works with primitive types, standard library containers, and user-defined types that have their own AbslHashValue implementations. The function efficiently mixes entropy from each field into the running hash state using CityHash-derived algorithms implemented in absl/hash/internal/city.h.

Where is the hash state implementation defined in the Abseil source code?

The hash state implementation is primarily defined in absl/hash/internal/hash.h, which contains the HashState and HashStateImpl classes. The public interface in absl/hash/hash.h delegates to these internal implementations, which handle the low-level mixing and entropy distribution using primitives from absl/hash/internal/city.h.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →