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

如何为std::pair编写模板哈希器?编译报错求助

问题:为std::pair编写哈希器时编译报错

尝试为std::pair编写通用哈希器,但编译时出现错误,怀疑编译器无法识别底层类型的哈希实现,代码如下:

#include <unordered_set>

struct Point
{
    std::pair<int, int> coords;
};

struct PointHasher;

struct Edge
{
    std::pair<Point, Point> pts;
};

template<typename T, typename U>
struct StdPairHasher
{
    size_t operator()(const std::pair<T, U>& pair) const
    {
        const auto& first_hash = std::hash<T>()(pair.first); // Error
        return first_hash ^ (std::hash<U>()(pair.second) + 0x9e3779b9 + (first_hash << 6) + (first_hash >> 2));
    }
};

struct EdgeHasher
{
    size_t operator()(const Edge& e) const { return StdPairHasher<Point, Point>()(e.pts); }
};

int main()
{
    std::unordered_set<Edge, EdgeHasher> s;

    return 0;
}

struct PointHasher
{
    size_t operator()(const Point& point) const { return StdPairHasher<int, int>()(point.coords); }
};

编译错误信息:

1>ConsoleApplication9.cpp(20,46): error C2064: term does not evaluate to a function taking 1 arguments
1>ConsoleApplication9.cpp(20,46):
1>the template instantiation context (the oldest one first) is
1>  ConsoleApplication9.cpp(27,80):
1>  see reference to class template instantiation 'StdPairHasher<Point,Point>' being compiled
1>  ConsoleApplication9.cpp(18,12):
1>  while compiling class template member function 'size_t StdPairHasher<Point,Point>::operator ()(const std::pair<Point,Point> &) const'
1>      ConsoleApplication9.cpp(27,46):
1>      see the first reference to 'StdPairHasher<Point,Point>::operator ()' in 'EdgeHasher::operator ()'
1>ConsoleApplication9.cpp(20,32): error C2530: 'first_hash': references must be initialized
1>ConsoleApplication9.cpp(21,16): error C3536: 'first_hash': cannot be used before it is initialized
1>ConsoleApplication9.cpp(21,42): error C2064: term does not evaluate to a function taking 1 arguments

错误原因

  1. 缺少自定义类型的哈希特化:标准库没有为自定义的Point类型提供std::hash特化,StdPairHasher<Point, Point>尝试调用std::hash<Point>()时,编译器找不到对应的函数,触发C2064错误。
  2. 代码顺序问题:PointHasher的定义在main之后,且没有关联到StdPairHasher的哈希逻辑中,即使定义了也无法被StdPairHasher使用。
  3. 引用初始化错误:const auto& first_hash试图绑定std::hash<T>()(pair.first)返回的临时值,虽然语法上const引用可以绑定临时对象,但由于前面的哈希调用失败,导致first_hash未正确初始化,触发后续的C2530和C3536错误。

修复方案

1. 让StdPairHasher支持自定义哈希器

修改模板,允许传入针对T和U的自定义哈希器,避免依赖std::hash的默认特化。

2. 调整代码顺序

将PointHasher的定义移到EdgeHasher之前,确保使用时已定义。

3. 修正哈希值的存储方式

将first_hash改为值类型,避免引用带来的初始化问题。


修复后的代码

#include <unordered_set>

struct Point
{
    std::pair<int, int> coords;
};

// 提前定义PointHasher
struct PointHasher
{
    size_t operator()(const Point& point) const;
};

struct Edge
{
    std::pair<Point, Point> pts;
};

// 修改StdPairHasher,支持自定义哈希器
template<typename T, typename U, typename HashT = std::hash<T>, typename HashU = std::hash<U>>
struct StdPairHasher
{
    size_t operator()(const std::pair<T, U>& pair) const
    {
        auto first_hash = HashT()(pair.first);
        auto second_hash = HashU()(pair.second);
        // 使用更合理的哈希组合方式,降低碰撞概率
        return first_hash ^ (second_hash << 1) + 0x9e3779b9 + (first_hash << 6) + (first_hash >> 2);
    }
};

// 实现PointHasher的operator()
size_t PointHasher::operator()(const Point& point) const 
{ 
    return StdPairHasher<int, int>()(point.coords); 
}

struct EdgeHasher
{
    size_t operator()(const Edge& e) const 
    { 
        return StdPairHasher<Point, Point, PointHasher, PointHasher>()(e.pts); 
    }
};

int main()
{
    std::unordered_set<Edge, EdgeHasher> s;

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:34:57