整数->ポインター変換規則


19

次のコードを検討してください。

void f(double p) {}
void f(double* p) {}

int main()
{ f(1-1); return 0; }

MSVC 2017はそれをコンパイルしません。と1-1同じ0であるため、あいまいなオーバーロードされた呼び出しがあることを示しているため、に変換できますdouble*。他のトリックは、のような0x00Lまたはstatic_cast<int>(0)、いずれかの動作しません。を宣言しconst int Zero = 0て呼び出しf(Zero)ても同じエラーが発生します。それは場合にのみ正しく動作Zeroではありませんconst

同じ問題がGCC 5以下に当てはまるようですが、GCC 6には当てはまりません。これがC ++標準の一部であるか、既知のMSVCバグであるか、コンパイラーの設定であるかどうか知りたいです。おおざっぱなグーグルは結果をもたらさなかった。

回答:


18

MSVC 1-1はNULLポインター定数と見なされます。これは、値0を持つすべての整数定数式がnullポインター定数であるC ++ 03の標準によって正しかったが、CWG問題903の C ++ 11の場合、ゼロ整数リテラルのみがnullポインター定数になるように変更されました。これは重大な変更であり、例でわかるように、また標準で文書化されているように、C ++ 14標準(ドラフトN4140)の[diff.cpp03.conv]を参照してください。

MSVCはこの変更を適合モードでのみ適用します。したがって、コードは/permissive-フラグでコンパイルされますが、変更はMSVC 2019でのみ実装されたと思いますこちらを参照してください

GCCの場合、GCC 5のデフォルトはC ++ 98モードですが、GCC 6以降のデフォルトはC ++ 14モードです。そのため、動作の変更はGCCバージョンに依存しているようです。

f引数としてnullポインター定数を指定して呼び出す場合、nullポインター定数は任意のポインター型のnullポインター値に変換でき、この変換はint(または任意の整数型)の変換と同じランクを持つため、呼び出しはあいまいです。にdouble


-1

コンパイラーは[over.match][conv]、より具体的には[conv.fpint]と[conv.ptr] に従って正しく動作します。

標準の変換シーケンスは、[何とか何とか]ゼロまたは1つの[...]浮動小数点整数変換、ポインター変換、[...]です。

そして

整数型またはスコープ外の列挙型のprvalueは、浮動小数点型のprvalueに変換できます。可能であれば結果は正確です[何とか何とか]

そして

NULLポインター定数は、値がゼロまたは[...]の整数リテラルです。nullポインター定数はポインター型に変換できます。結果は、その型のnullポインター値です。

現在、オーバーロードの解決は、すべての候補関数の中で最も一致するものを選択することです(これは、楽しい機能として、呼び出しの場所でアクセスする必要さえありません!)。最適な一致は、正確なパラメーターを持つもの、または可能な限り変換が最も少ないものです。ゼロまたは1つの標準変換が発生する可能性があり(...すべてのパラメーターについて)、ゼロは1よりも「優れています」。

(1-1)は値を持つ整数リテラルです0

あなたがゼロ整数リテラルに変換することができ、それぞれのいずれかdoubleまたはdouble*(もしくはnullptr_t)で正確に一つの変換。したがって、これらの関数が複数宣言されていると(例のように)、複数の候補が存在し、すべての候補が同等に良好である場合、最適な一致は存在しません。あいまいで、コンパイラは文句を言うのは正しいです。


1
どのように整数リテラルは?これは、値と演算子を持つ2つの整数リテラルを含む式です。1-11-
クルミ

@walnut:おそらく、「2桁の数字、8進数の数字、数字、または16進数のシーケンス」という厄介な表現を参照しています。これは不幸にも「明白な」何かを表す非常に不幸な表現であり、そうではない(つまり、マイナス文字を除く)ことを示唆しています。「数字」だけで、そして「数字」の定義(0 ... 9の1つ)に従って表現的には負のリテラル(など-1)を持つことはできません。ただし、デフォルトのタイプはsignedであるため、これは明らかに必要であり、それは明らかに可能です(そして広く受け入れられています)。
デイモン

1
標準リンクに示されているinteger-literalの文法を参照していますが、これはと一致しません1-1。C ++には負の整数リテラルはありません。-1で構成された表現である1(署名されたタイプの)整数リテラルと-単項マイナス演算子。cppreference.comの「注意」セクションも参照してください。
クルミ

文法にそれがないことは確かに本当ですが、それは広く重要ではありません。必要に応じて、そして定義上、C ++に負のリテラルがあります。明示的にを追加しない限りu、リテラルは定義ごとに署名されているためです。符号付きタイプに負の値があります(可能な値の約50%が負です)。文法が(私が知らない理由で)このように誤解を招くのは残念です、そして技術的には(文法によると)-1は正のリテラルですが、否定されますが、他のすべての方法ではもちろん負ですリテラル。3 + 4は文字通りです。
デイモン

ちなみに-試しました0U。同じ問題。私が試していないのはenum価値です。名前の付いたものは状況を変えたかもしれません。私は長い式を書いてしまったdecltyperemove_reference
user1334767
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.