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

时间:2019-01-11 13:12:50

标签: c++ gcc hash clang c++17

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>的默认构造函数已(隐式)删除了。 请参见herehere自己进行验证。

Visual Studio会编译它。显然,它返回 0 672807365

问题1: GCC和Clang是否仍然只是缺少C ++ 17功能,因为这不是一个高优先级的功能?还是我错过了什么?

第二季度:我可以自己专门化它,然后像Visual Studio一样返回 0 672807365吗? 没有其他值,例如一些质数,最好将其与其他哈希值结合使用?


更新

由于我有限的汇编程序知识,我认为Visual Studio将返回0。实际上,它正在返回672807365eax中的值)。 因此,我的第二个问题基本上可以回答自己:我将以我的专长返回0来解决此错误。

1 个答案:

答案 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类模板。您也可以打破一个定义规则。