web-dev-qa-db-ja.com

GCCとClangがC ++ 17でstd :: hash <std :: nullptr_t>をコンパイルしない

https://en.cppreference.com/w/cpp/utility/hash には、C++ 17以降

テンプレートstd :: hashを宣言する各標準ライブラリヘッダーは、std :: nullptr_tおよびすべてのcv非修飾算術型(拡張整数型を含む)、すべての列挙型、およびすべてのポインター型に対して、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

Q1:確かにこれは優先度の高い機能ではないので、GCCとClangにはこのC++ 17機能がまだありませんか?それとも何か不足していますか?

Q2:自分で特化して戻ることはできますか? 0 672807365はVisual Studioに似ていますか? その他の値はありません。いくつかの素数、他のハッシュと組み合わせる方が良いですか?


更新

アセンブラに関する知識が限られていたため、Visual Studioが0を返すと思いました。実際、672807365eaxの値)を返しています。したがって、私の2番目の質問は基本的にそれ自体で答えます。このバグを回避するには、専門分野でnotを返します0

23
sebrockm

このプログラムは正しいですか?

cppreference.comは正しいです。最新のC++標準ドラフトから:

[unord.hash]/2

以下で説明するように、ハッシュの各特殊化は有効または無効になっています。 [...]テンプレートハッシュを宣言する各ヘッダーは、nullptr_­thashの有効化された特殊化、およびすべてのcv修飾なしの算術、列挙、およびポインター型を提供します。

<functional>hashテンプレートを宣言しているため1、それはstd::hash<std::nullptr_t>の有効な特殊化を提供する必要があります。 サンプルプログラムは、適合するC++ 17実装で受け入れられる必要があります。


なぜそうではないのですか?

C++ 17はまだ若いので、一部の微妙な機能がまだ欠けているか、最近のコンパイラーにバグがある可能性があります。 MCVEは、gccおよびclangの開発/ 実験的 ブランチで受け入れられます。

それを受け入れるGCCの開発バージョンは見つかりませんでした。これがバグレポートが Lightness Races in Orbitstd :: hash not implement を参照)によって発生し、-によって修正された理由です Jonathan Wakelyrevision267845 を参照)(そして ゼロを返す を参照)。


実装が修正されるのを待っている間にプログラムを修正する方法は?

自分で専門化してVisual Studioのように0を返すことはできますか?

未定義の動作を示すコードを記述します2。自己責任で行ってください。十分に文書化してください。たとえば、以下をseparate翻訳単位に入れます。

#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) [functional.syn] を参照してください。

2) あなたは のみ許可 プログラムで定義された型(nullptr_­tはそうではありません)のstdクラステンプレートを特殊化します。また、1つの定義ルールを破ることもできます。

19
YSC