如何为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
错误原因
- 缺少自定义类型的哈希特化:标准库没有为自定义的
Point类型提供std::hash特化,StdPairHasher<Point, Point>尝试调用std::hash<Point>()时,编译器找不到对应的函数,触发C2064错误。 - 代码顺序问题:
PointHasher的定义在main之后,且没有关联到StdPairHasher的哈希逻辑中,即使定义了也无法被StdPairHasher使用。 - 引用初始化错误:
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
相关产品推荐
相关产品推荐

