在https://en.cppreference.com/w/cpp/utility/hash上说,自C ++ 17起
每个声明模板std :: hash的标准库头 为std :: nullptr_t提供启用的std :: hash专业化功能,并 所有简历不合格算术类型(包括任何扩展整数) 类型),所有枚举类型和所有指针类型。
因此,符合C ++ 17的编译器应编译此小程序:
#include <functional>
int main()
{
std::hash<std::nullptr_t> h;
return h(nullptr);
}
但是,GCC和Clang都报告了一个错误,指出std::hash<std::nullptr_t>
的默认构造函数已(隐式)删除了。
请参见here和here自己进行验证。
Visual Studio会编译它。显然,它返回 0
672807365
。
问题1: GCC和Clang是否仍然只是缺少C ++ 17功能,因为这不是一个高优先级的功能?还是我错过了什么?
第二季度:我可以自己专门化它,然后像Visual Studio一样返回 0
672807365
吗? 没有其他值,例如一些质数,最好将其与其他哈希值结合使用?
由于我有限的汇编程序知识,我认为Visual Studio将返回0
。实际上,它正在返回672807365
(eax
中的值)。
因此,我的第二个问题基本上可以回答自己:我将不以我的专长返回0
来解决此错误。
答案 0 :(得分:18)
cppreference.com是正确的。根据最新的C ++标准草案:
[unord.hash]/2
启用或禁用哈希的每个特殊化,如下所述。 [...]每个声明模板哈希的标头都为
hash
提供了nullptr_t
的已启用特殊化,以及所有cv不合格的算术,枚举和指针类型。
由于<functional>
声明了hash
模板 1 ,因此它必须为std::hash<std::nullptr_t>
提供启用的专业化。 任何兼容的C ++ 17实现都应接受您的示例程序。
C ++ 17仍然很年轻,一些微妙的功能可能仍然缺少,或者在最近的编译器上有错误。请放心,gcc和clang在您的development / experimental分支中接受了您的MCVE。
尽管如此,我们找不到接受它的GCC开发版本;这就是为什么{strong> Lightness Races in Orbit(请参见std::hash not implemented)提出错误报告并由Jonathan Wakely (请参见revision267845)对此错误报告进行修正的原因({ {3}}。
我可以自己专门化它,然后像Visual Studio一样返回0吗?
您将要编写显示未定义行为 2 的代码。自行承担风险。妥善记录。例如,将以下内容放在单独翻译单元中:
#include <functional>
#include <type_traits>
static_assert(
false == std::is_default_constructible_v<std::hash<std::nullptr_t>>,
"Explanation"
);
这会警告您的同事,并要求他们手动删除您对std::hash<std::nullptr_t>
的专长,而不是使他们感到讨厌的编译错误。
1)参见returns zero。
2)您是[functional.syn]
的专家,专门为程序定义的类型(不是std
)设计nullptr_t
类模板。您也可以打破一个定义规则。