[英]GCC and Clang don't compile std::hash<std::nullptr_t> in C++17
On https://en.cppreference.com/w/cpp/utility/hash it says that since C++17在https://en.cppreference.com/w/cpp/utility/hash上说,自从 C++17
Each standard library header that declares the template std::hash provides enabled specializations of std::hash for std::nullptr_t and all cv-unqualified arithmetic types (including any extended integer types), all enumeration types, and all pointer types.
每个声明模板 std::hash 的标准库头都为 std::nullptr_t 和所有 cv 非限定算术类型(包括任何扩展整数类型)、所有枚举类型和所有指针类型提供了 std::hash 的启用特化。
So, a C++17 compliant compiler should compile this little program:所以,一个 C++17 兼容的编译器应该编译这个小程序:
#include <functional>
int main()
{
std::hash<std::nullptr_t> h;
return h(nullptr);
}
However, GCC and Clang both are reporting an error saying that the default constructor of std::hash<std::nullptr_t>
is (implicitly) deleted.但是,GCC 和 Clang 都报告错误,指出
std::hash<std::nullptr_t>
的默认构造函数已(隐式)删除。 See here and here to verify it yourself.请参阅此处和此处自行验证。
Visual Studio does compile it. Visual Studio会编译它。 Apparently it returns
0
672807365
.显然它返回
0
672807365
。
Q1: Are GCC and Clang simply still missing this C++17 feature, as admittedly this is not a high priority one? Q1: GCC 和 Clang 是否仍然缺少这个 C++17 特性,诚然这不是一个高优先级的特性? Or am I missing something?
或者我错过了什么?
Q2: Can I just specialize it myself and return 0
672807365
like Visual Studio? Q2:我可以自己专门化它并像 Visual Studio 一样返回
0
672807365
吗? Wouldn't some other value, eg some prime, be better for combining it with other hashes?其他一些值,例如一些素数,不是更适合将它与其他散列相结合吗?
Due to my limited assembler knowledge I thought that Visual Studio is returning 0
.由于我有限的汇编知识,我认为 Visual Studio 正在返回
0
。 In fact, it is returning 672807365
(the value in eax
).事实上,它返回
672807365
( eax
的值)。 So, my second question basically answers itself: I will not return 0
in my specialization to workaround this bug.所以,我的第二个问题基本上是自己回答的:我不会在我的专业中返回
0
来解决这个错误。
cppreference.com is right. cppreference.com 是对的。 From the latest C++ Standard draft:
来自最新的 C++ 标准草案:
[unord.hash]/2
Each specialization of hash is either enabled or disabled, as described below.
如下所述,散列的每个特化要么被启用,要么被禁用。 [...] Each header that declares the template hash provides enabled specializations of
hash
fornullptr_t
and all cv-unqualified arithmetic, enumeration, and pointer types.[...] 每个声明模板散列的标头都为
nullptr_t
和所有 cv 非限定算术、枚举和指针类型提供了启用的hash
nullptr_t
。
Since <functional>
declares the hash
template 1 , it must provide an enabled specialization for std::hash<std::nullptr_t>
.由于
<functional>
声明了hash
模板1 ,它必须为std::hash<std::nullptr_t>
提供一个启用的std::hash<std::nullptr_t>
。 Your example program should be accepted by any conforming C++17 implementation .任何符合 C++17 的实现都应该接受您的示例程序。
C++17 being still young, some subtle features might be missing still or buggy on recent compilers. C++17 还很年轻,一些微妙的特性可能在最近的编译器上仍然缺失或有问题。 Be reassured, your MCVE is accepted by gcc and clang in their development/ experimental branches.
请放心,您的 MCVE 已被 gcc 和 clang 在其开发/实验分支中接受。
We couldn't find a development version of GCC accepting it though;但是我们找不到接受它的 GCC 开发版本; this is why a bug report has been raised byLightness Races in Orbit (see std::hashstd::nullptr_t not implemented) and fixed by Jonathan Wakely (see revision267845 ) (and it returns zero ).
这就是为什么Lightness Races in Orbit (参见std::hashstd::nullptr_t未实现)提出错误报告并由Jonathan Wakely修复(参见修订版267845 )(并返回零)的原因。
Can I just specialize it myself and return 0 like Visual Studio?
我可以自己专门化它并像 Visual Studio 一样返回 0 吗?
You would be writing code that will exhibit Undefined Behavior 2 .您将编写将展示未定义行为2 的代码。 Do it at your own risk.
风险自负。 Document it well.
好好记录一下。 For instance, put the following in a separate translation unit:
例如,将以下内容放在单独的翻译单元中:
#include <functional>
#include <type_traits>
static_assert(
false == std::is_default_constructible_v<std::hash<std::nullptr_t>>,
"Explanation"
);
This will warn your colleagues and ask them to manually remove your specialization of std::hash<std::nullptr_t>
rather than get them a nasty compilation error.这将警告您的同事并要求他们手动删除您对
std::hash<std::nullptr_t>
专业化,而不是让他们出现令人讨厌的编译错误。
1) See [functional.syn]
. 1)参见
[functional.syn]
。
2) You are only allowed to specialize std
class templates for program-defined types (which nullptr_t
isn't). 2)您只能为程序定义的类型(
nullptr_t
不是)专门化std
类模板。 You could also break the One Definition Rule.你也可以打破一个定义规则。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.