GCC12.2中带auto返回值的哈希函数静态断言报错问题
GCC 12.2中
unordered_map哈希函数可调用性错误的原因与解决 在GCC 12.2中运行以下C++代码时,会触发hash function must be invocable with an argument of key type的静态断言错误:
#include <cstddef> #include <unordered_map> #include <functional> struct OUTER { class KEY { public: bool operator==(KEY const&) const; struct Hash { auto operator()(KEY const&) const { return std::hash<size_t>{}(10); }; }; }; std::unordered_map<KEY, int, KEY::Hash> m; bool test(KEY const& ident) { return m.end() != m.find(ident); } };
对应的错误核心信息:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable_policy.h:1268:23: error: static assertion failed: hash function must be invocable with an argument of key type 1268 | static_assert(__is_invocable<const _Hash&, const _Key&>{}, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable_policy.h:1268:23: note: 'std::__is_invocable<const OUTER::KEY::Hash&, const OUTER::KEY&>()' evaluates to false
疑问:OUTER::KEY::Hash::operator()明明接受KEY const&作为参数,为何会触发这个错误?
错误原因
问题出在哈希函数的返回类型推导上:
- 哈希函数
Hash::operator()使用了auto作为返回类型,C++中auto返回类型的推导需要等到函数体可见且上下文类型完整才能完成。 - 当编译器处理
OUTER类内的std::unordered_map<KEY, int, KEY::Hash> m;时,OUTER类本身尚未完成定义,嵌套类KEY的Hash成员函数的auto返回类型无法被推导出来。 - GCC的
std::unordered_map实现中,静态断言__is_invocable会检查哈希函数是否能被正确调用,而返回类型未确定的函数会被判定为不可调用,因此触发断言错误。
简言之:auto返回类型在类定义完成前无法确定,导致编译器认为哈希函数的签名不合法。
解决方法
有两种可行的修复方式:
1. 显式指定哈希函数的返回类型
将auto替换为明确的std::size_t(哈希函数的标准返回类型):
#include <cstddef> #include <unordered_map> #include <functional> struct OUTER { class KEY { public: bool operator==(KEY const&) const { return true; } // 补充定义避免链接错误 struct Hash { // 替换auto为std::size_t std::size_t operator()(KEY const&) const { return std::hash<size_t>{}(10); }; }; }; std::unordered_map<KEY, int, KEY::Hash> m; bool test(KEY const& ident) { return m.end() != m.find(ident); } };
2. 将哈希函数移到KEY类外部定义
如果需要保留auto返回类型,可以把Hash的operator()移到KEY类外部定义,确保类型推导在完整上下文进行:
#include <cstddef> #include <unordered_map> #include <functional> struct OUTER { class KEY { public: bool operator==(KEY const&) const { return true; } struct Hash { auto operator()(KEY const&) const; }; }; std::unordered_map<KEY, int, KEY::Hash> m; bool test(KEY const& ident) { return m.end() != m.find(ident); } }; // 在类外部定义哈希函数,此时OUTER和KEY都已完整定义 auto OUTER::KEY::Hash::operator()(KEY const&) const { return std::hash<size_t>{}(10); }
内容的提问来源于stack exchange,提问作者William Navarre
相关产品推荐
相关产品推荐

