# How to Implement Custom Hash Functions and Equality Predicates for absl::flat_hash_map

> Learn to implement custom hash functions and equality predicates for absl::flat_hash_map by providing your own Hash and Eq types with is transparent for heterogeneous lookups.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: how-to-guide
- Published: 2026-07-11

---

**To implement custom hash functions and equality predicates for `absl::flat_hash_map`, supply your own `Hash` and `Eq` types as the third and fourth template arguments, ensuring they expose `is_transparent` for heterogeneous lookup and implement the required operator overloads.**

The `absl::flat_hash_map` container in the Abseil C++ library provides high-performance associative array operations backed by the SwissTable algorithm. While it defaults to the Abseil hashing framework (`absl::Hash`), the template parameters allow you to inject custom behavior for specialized key types or heterogeneous lookup requirements. Understanding the specific requirements documented in the Abseil source code ensures your custom functors integrate seamlessly with the container's internal machinery.

## Understanding flat_hash_map Template Parameters

The `absl::flat_hash_map` class template accepts four parameters, with the last two controlling hashing and equality:

```cpp
template <class K, class V,
          class Hash = DefaultHash,
          class Eq   = DefaultEq>
class flat_hash_map { … };

```

The **default hash** resolves to `absl::container_internal::hash_default_hash<K>`, and the **default equality** resolves to `absl::container_internal::hash_default_eq<K>`. These defaults are defined in [`absl/container/hash_container_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/container/hash_container_defaults.h) and ultimately implemented in [`absl/container/internal/hash_function_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/container/internal/hash_function_defaults.h). If your key type defines inner types named `absl_container_hash` and `absl_container_eq`, the library automatically detects them via the `HashEq<T>` specialization located at lines 334–344 in [`hash_function_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/hash_function_defaults.h).

## Requirements for Custom Hash and Equality Functors

Custom functors must satisfy two specific conditions to work correctly with `absl::flat_hash_map` as documented in [`absl/container/flat_hash_map.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/container/flat_hash_map.h) (lines 95–104).

### Enabling Heterogeneous Lookup with is_transparent

To support **heterogeneous lookup** (e.g., finding a `std::string` key using `absl::string_view`), your custom functors must define a nested type:

```cpp
using is_transparent = void;

```

This marker type signals the container to enable overloads that accept lookup keys differing from the stored key type. Without this definition, the container restricts lookups to the exact key type, degrading flexibility.

### Required Callable Signatures

Your custom functors must implement specific operator overloads:

- **Hash functor**: Must provide `size_t operator()(U val) const` for any lookup type `U` you intend to support.
- **Equality functor**: Must provide `bool operator()(U lhs, V rhs) const` that returns `true` when the arguments compare equal. You typically need three overloads: `(Key, Key)`, `(Key, Lookup)`, and `(Lookup, Key)` to handle heterogeneous comparisons bidirectionally.

## Implementation Examples

The following examples demonstrate different strategies for providing custom hash and equality logic to `absl::flat_hash_map`.

### Example 1: Custom Functors for User-Defined Structs

For a custom `Point` struct, define separate hash and equality functors that support heterogeneous lookup with `std::pair<int,int>`:

```cpp
struct Point {
  int x, y;
};

struct PointHash {
  using is_transparent = void;
  
  std::size_t operator()(const Point& p) const {
    return (static_cast<std::size_t>(p.x) << 32) ^ static_cast<std::size_t>(p.y);
  }
  
  std::size_t operator()(const std::pair<int,int>& pr) const {
    return (static_cast<std::size_t>(pr.first) << 32) ^ static_cast<std::size_t>(pr.second);
  }
};

struct PointEq {
  using is_transparent = void;
  
  bool operator()(const Point& a, const Point& b) const {
    return a.x == b.x && a.y == b.y;
  }
  
  bool operator()(const Point& a, const std::pair<int,int>& pr) const {
    return a.x == pr.first && a.y == pr.second;
  }
  
  bool operator()(const std::pair<int,int>& pr, const Point& a) const {
    return operator()(a, pr);
  }
};

// Usage
absl::flat_hash_map<Point, std::string, PointHash, PointEq> point_map;
point_map.emplace(Point{1, 2}, "A");

// Heterogeneous lookup with pair<int,int>
auto it = point_map.find(std::make_pair(1, 2));

```

### Example 2: Embedded Hash and Equality Types

You can embed the functors directly within your key type using the special names `absl_container_hash` and `absl_container_eq`. This allows `absl::flat_hash_map` to automatically deduce the custom functors without explicit template arguments:

```cpp
struct UserId {
  std::string id;
  
  struct absl_container_hash {
    using is_transparent = void;
    
    std::size_t operator()(absl::string_view v) const {
      return absl::Hash<absl::string_view>{}(v);
    }
    
    std::size_t operator()(const UserId& u) const {
      return absl::Hash<std::string>{}(u.id);
    }
  };
  
  struct absl_container_eq {
    using is_transparent = void;
    
    bool operator()(absl::string_view lhs, absl::string_view rhs) const {
      return lhs == rhs;
    }
    
    bool operator()(const UserId& lhs, const UserId& rhs) const {
      return lhs.id == rhs.id;
    }
    
    bool operator()(absl::string_view lhs, const UserId& rhs) const {
      return lhs == rhs.id;
    }
    
    bool operator()(const UserId& lhs, absl::string_view rhs) const {
      return lhs.id == rhs;
    }
  };
};

// Template arguments deduced automatically
absl::flat_hash_map<UserId, int> id_to_score;
id_to_score.emplace(UserId{"alice"}, 42);

// Lookup with string_view - no temporary construction needed
auto it = id_to_score.find(absl::string_view("alice"));

```

### Example 3: Using Lambdas with C++20

For quick one-off customization, you can use lambdas (C++20) by wrapping them in the template declaration:

```cpp
auto lambda_hash = [](const std::string& s) -> std::size_t {
  return absl::Hash<std::string>{}(s);
};

struct LambdaEq {
  using is_transparent = void;
  bool operator()(const std::string& a, const std::string& b) const {
    return a == b;
  }
};

absl::flat_hash_map<std::string, double,
                    decltype(lambda_hash), LambdaEq> price_map(0, lambda_hash);
price_map["apple"] = 1.23;

```

## Summary

- **`absl::flat_hash_map`** accepts custom `Hash` and `Eq` types as the third and fourth template parameters, defaulting to Abseil's internal hash defaults.
- **Heterogeneous lookup** requires your functors to define `using is_transparent = void;` as documented in [`flat_hash_map.h`](https://github.com/abseil/abseil-cpp/blob/main/flat_hash_map.h) lines 95–100.
- **Hash functors** must implement `size_t operator()(U val) const` for supported lookup types.
- **Equality functors** must implement `bool operator()(U lhs, V rhs) const` for all comparison combinations.
- **Embedded functors** named `absl_container_hash` and `absl_container_eq` enable automatic detection via the `HashEq<T>` machinery in [`hash_function_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/hash_function_defaults.h).

## Frequently Asked Questions

### What is the default hash function used by absl::flat_hash_map?

By default, `absl::flat_hash_map` uses `absl::container_internal::hash_default_hash<K>` as defined in [`absl/container/internal/hash_function_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/container/internal/hash_function_defaults.h). This default integrates with the Abseil hashing framework and supports the standard hashing protocol for built-in and common types.

### Why do I need to define is_transparent in my custom functors?

The nested type `is_transparent` enables **heterogeneous lookup**, allowing you to search for keys using types different from the stored key type (e.g., looking up a `std::string` key with `absl::string_view`). Without this definition, the container restricts lookups to exact key matches, preventing optimizations that avoid unnecessary conversions.

### Can I use lambdas for custom hash functions in absl::flat_hash_map?

Yes, you can use lambdas for custom hash functions, particularly with C++20. You must declare the lambda (or wrap it in a struct) and pass its type via `decltype` to the template parameters, then provide the lambda instance as a constructor argument to initialize the map's hasher.

### How do I enable automatic hash detection for my custom type?

Define inner types named **`absl_container_hash`** and optionally **`absl_container_eq`** within your key class. According to the `HashEq<T>` specialization in [`absl/container/internal/hash_function_defaults.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/container/internal/hash_function_defaults.h) (lines 334–344), the library automatically detects these types and uses them as the hash and equality functors when you declare `absl::flat_hash_map<MyKey, Value>` without explicit template arguments.