简体   繁体   English

GCC 和 Clang 不编译 std::hash<std::nullptr_t> 在 C++17 中

[英]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++17https://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?其他一些值,例如一些素数,不是更适合将它与其他散列相结合吗?


Update更新

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 ).事实上,它返回672807365eax的值)。 So, my second question basically answers itself: I will not return 0 in my specialization to workaround this bug.所以,我的第二个问题基本上是自己回答的:我不会在我的专业中返回0来解决这个错误。

Is this program correct?这个程序正确吗?

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 for nullptr_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 的实现都应该接受您的示例程序


Why it is not though?为什么不是呢?

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 )(并返回零)的原因。


How to fix your program while you're waiting for your implementation to get fixed?如何在等待实现修复的同时修复您的程序?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM