You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20透明哈希配置后,unordered_set为何无法按std::pair搜索?

问题:C++20透明哈希无法直接用std::pair搜索unordered_set的原因

需求背景

我们有自定义结构体Pixel2DWithCount,需要实现两个目标:

  • 将像素存储在unordered_set中
  • 直接通过两个整数值在集合中搜索

C++20之前的实现

只能通过创建临时Pixel2DWithCount对象进行搜索,代码如下:

#include <functional>
#include <iostream>
#include <unordered_set>

struct Pixel2DWithCount {
  int x, y;
  Pixel2DWithCount(int x_, int y_): x(x_), y(y_){}
  inline friend bool operator==(const Pixel2DWithCount &first, const Pixel2DWithCount &second) noexcept{
        return first.x == second.x && first.y == second.y;
    }
};

struct Pixel2DWithCountHasher {
  std::hash<long> _hasher;
  size_t operator()(const Pixel2DWithCount& p) const {
    constexpr size_t _shift_bits_num = sizeof(int) * 8;
    return _hasher(static_cast<long>(p.x) << _shift_bits_num |
                  static_cast<long>(p.y));
  }
};

int main(){
    Pixel2DWithCount p1(1, 2);
    Pixel2DWithCount p2(2, 2);
    std::unordered_set<Pixel2DWithCount, Pixel2DWithCountHasher> s{p1, p2};
    std::cout<<(s.find(p1) != s.end());
}

这种方式存在临时对象创建的性能开销,因此希望在C++20中利用透明哈希特性直接通过std::pair<int, int>搜索。

C++20的尝试代码

为支持透明哈希,实现了兼容Pixel2DWithCount和std::pair<int, int>的哈希器和比较器,但调用find(std::pair<int, int>)时编译器报错:no matching function for call to std::unordered_set<Pixel2DWithCount, Pixel2DWithCountHasher, ComparePixel2DWithCount>::find(std::pair<int, int>)。尝试的代码如下:

struct ComparePixel2DWithCount{
    bool operator()(const Pixel2DWithCount &first, const Pixel2DWithCount &second) const noexcept{
        return first.x == second.x && first.y == second.y;
    }
    bool operator()(const std::pair<int, int> &first, const Pixel2DWithCount &second) const noexcept{
        return first.first == second.x && first.second == second.y;
    }

    bool operator()(const Pixel2DWithCount &first, const std::pair<int, int> &second) const noexcept{
        return first.x == second.first && first.y == second.second;
    }
};

struct Pixel2DWithCountHasher {
  std::hash<long> _hasher;
  size_t operator()(const std::pair<int, int>& pair) const {
    constexpr size_t _shift_bits_num = sizeof(int) * 8;
    return _hasher(static_cast<long>(pair.first) << _shift_bits_num | 
    static_cast<long>(pair.second));
  }
   size_t operator()(const Pixel2DWithCount& p) const {
    constexpr size_t _shift_bits_num = sizeof(int) * 8;
    return _hasher(static_cast<long>(p.x) << _shift_bits_num |
                   static_cast<long>(p.y));
   }
};

int main(){
  Pixel2DWithCount p1(1, 2);
  Pixel2DWithCount p2(2, 2);
  std::unordered_set<Pixel2DWithCount, 
                     Pixel2DWithCountHasher, 
                     ComparePixel2DWithCount> s{p1, p2};
  // 此处调用find会报错
  // s.find(std::make_pair(1,2));
}

错误原因

要让unordered_set支持透明哈希的异构查找,必须满足两个关键条件:

  1. 哈希器必须声明is_transparent类型:需要在Pixel2DWithCountHasher结构体中添加using is_transparent = void;,告诉标准库该哈希器支持透明操作,可处理不同类型的输入。
  2. 比较器同样需要声明is_transparent类型:在ComparePixel2DWithCount结构体中添加using is_transparent = void;,确保标准库识别到比较器支持跨类型比较。

标准库的unordered_set::find只有在哈希器和比较器都提供了is_transparent类型时,才会启用异构查找的重载版本。你的代码中缺少这两个类型定义,因此编译器无法找到接受std::pair<int, int>的find重载。

修正后的代码示例

在哈希器和比较器中添加is_transparent声明即可解决问题:

struct ComparePixel2DWithCount{
    using is_transparent = void; // 添加透明声明
    bool operator()(const Pixel2DWithCount &first, const Pixel2DWithCount &second) const noexcept{
        return first.x == second.x && first.y == second.y;
    }
    bool operator()(const std::pair<int, int> &first, const Pixel2DWithCount &second) const noexcept{
        return first.first == second.x && first.second == second.y;
    }

    bool operator()(const Pixel2DWithCount &first, const std::pair<int, int> &second) const noexcept{
        return first.x == second.first && first.y == second.second;
    }
};

struct Pixel2DWithCountHasher {
  using is_transparent = void; // 添加透明声明
  std::hash<long> _hasher;
  size_t operator()(const std::pair<int, int>& pair) const {
    constexpr size_t _shift_bits_num = sizeof(int) * 8;
    return _hasher(static_cast<long>(pair.first) << _shift_bits_num | 
    static_cast<long>(pair.second));
  }
   size_t operator()(const Pixel2DWithCount& p) const {
    constexpr size_t _shift_bits_num = sizeof(int) * 8;
    return _hasher(static_cast<long>(p.x) << _shift_bits_num |
                   static_cast<long>(p.y));
   }
};

int main(){
  Pixel2DWithCount p1(1, 2);
  Pixel2DWithCount p2(2, 2);
  std::unordered_set<Pixel2DWithCount, 
                     Pixel2DWithCountHasher, 
                     ComparePixel2DWithCount> s{p1, p2};
  // 现在可以直接用pair搜索
  if (s.find(std::make_pair(1,2)) != s.end()) {
      std::cout << "Found pixel (1,2)\n";
  }
}

内容的提问来源于stack exchange,提问作者Ruotong Jia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:38:10