每周技巧 #152:`AbslHashValue` 与你

本节阅读量:

本文翻译自 Abseil 官网的 Tip of the Week #152: AbslHashValue and You

原文最初作为 TotW #152 发布于 2018 年 6 月 21 日。

作者:Matt Kulukundis

更新于 2020 年 4 月 6 日。

快捷链接:abseil.io/tips/152

我爱莫扎特,但我常常把它搞得一团糟。 —— Simon Rattle

absl::Hash 框架(https://abseil.io/docs/cpp/guides/hash)现在是 Swisstable 哈希表家族(absl::{flat,node}_hash_{set,map})的默认哈希实现。所有可由该框架哈希的类型,都会自动可用作 Swisstables 的 key。

如何使用它?

假设我们有一个简单的 Song 结构体(我们约定一首歌可以由这些字段唯一标识):

1
2
3
4
5
struct Song {
  std::string name;
  std::string artist;
  absl::Duration duration;
};

并且我们希望能够存储 absl::flat_hash_set<Song>absl::flat_hash_map<Song, CopyrightOwner>。我们只需要添加一个简单的友元函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
struct Song {
  std::string name;
  std::string artist;
  absl::Duration duration;

  template <typename H>
  friend H AbslHashValue(H h, const Song& s) {
    return H::combine(std::move(h), s.name, s.artist, s.duration);
  }

  // Include your implementation of operator == and != here
};

然后一切就能工作!

如何测试它?

我们提供 absl::VerifyTypeImplementsAbslHashCorrectly,用于验证某个类型是否正确实现了其重载。这个函数有几个要求:

  • 该类型必须正确实现 == 运算符。
  • 调用方必须提供该类型的一些实例,覆盖该类型的所有有趣表示。(例如,带有小尺寸优化的类型,应该包含使用小尺寸优化和不使用小尺寸优化的等价实例。)
1
2
3
4
5
6
7
8
TEST(MyType, SupportsAbslHash) {
  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
      MyType(),
      MyType(1, 2),
      MyType(2, 3),
      MyType(0, 0),
  }));
}

absl::VerifyTypeImplementsAbslHashCorrectly 还支持测试异构查找和自定义相等运算符。

感兴趣并想了解更多?请阅读 https://abseil.io/docs/cpp/guides/hash

每周技巧 #149:对象生命周期与 `= delete`

上一节

每周技巧 #153:不要使用 using 指示

下一节