nullptrをuintptr_tに変換できますか?異なるコンパイラは同意しません


10

このプログラムを考えてみましょう:

#include <cstdint>
using my_time_t = uintptr_t;

int main() {
    const my_time_t t = my_time_t(nullptr);
}

msvc v19.24でコンパイルできませんでした:

<source>(5): error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'my_time_t'
<source>(5): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type
<source>(5): error C2789: 't': an object of const-qualified type must be initialized
<source>(5): note: see declaration of 't'

Compiler returned: 2

しかし、clang(9.0.1)とgcc(9.2.1)はこのコードをエラーなしで「食べ」ます。

MSVCの動作は好きですが、標準で確認されていますか?言い換えれば、それはclang / gccのバグですか、これがgcc / clangからの正しい動作であるという標準を解釈することは可能ですか?


2
これを関数スタイルのキャストからのコピーの初期化として読みました。その後、コンパイラーは、「コンパイルできない場合でも」C ++キャストの1つとして解釈します。キャストがどのように解釈されるかについて、コンパイラ間に矛盾があるのか​​もしれません
wreckgar23

私の知る限り、MSVC v19.24はC ++ 11モードをサポートしていません。代わりにC ++ 14またはC ++ 17ですか?
クルミ

回答:


5

私の意見では、MSVCは標準に準拠していません。

私はこの答えをC ++ 17(ドラフトN4659)に基づいていますが、C ++ 14とC ++ 11には同等の表現があります。

my_time_t(nullptr)後置式であり、my_time_tはタイプであり(nullptr)、括弧で囲まれた初期化リスト内の単一の式であるため、明示的なキャスト式とまったく同じです。([expr.type.conv] / 2

明示的なキャストは、いくつかの異なる特定のC ++キャスト(拡張機能付き)、特にを試みreinterpret_castます。([expr.cast] /4.4)以前に試したキャストreinterpret_castconst_castandとstatic_cast(拡張機能と組み合わせて)ですが、これらのいずれもstd::nullptr_t整数型にキャストできません。

しかしreinterpret_cast<my_time_t>(nullptr)ため、成功するべきである[expr.reinterpret.cast] / 4種類の値がと言っstd::nullptr_tたかのように一体型に変換することができるreinterpret_cast<my_time_t>((void*)0)ので、可能である、my_time_t = std::uintptr_t全てのポインタ値を表すタイプ十分な大きさであり、この状態の下でなければなりません同じ標準段落でvoid*整数型への変換が可能です。

関数表記ではなくキャスト表記が使用されている場合、MSVCが変換を許可するのは特に奇妙です。

const my_time_t t = (my_time_t)nullptr;

1
うん。注意static_cast特に、いくつかの例は、(例えば、曖昧なベースにCスタイルのキャストが悪い形成されたトラップにCスタイルのキャストのはしごを意図しているstatic_castのではなくreinterpret_cast)、どれもがここで適用されません。
TC

my_time_t(nullptr)定義上はと同じなので(my_time_t)nullptr、MSVCは一方を受け入れて他方を拒否するのは間違いです。
Richard Smith

2

私は見つけることができますが、明示的な本で言及C ++標準ワーキングドラフト(2014年から)からその変換std::nullptr_t整数型には禁止されているが、このような変換が許可されていることは言及もありません!

ただし、からstd::nullptr_tへの変換のケースbool 明示的に言及されています。

4.12ブール変換
算術、スコープなし列挙、ポインター、またはメンバー型へのポインターのprvalueは、bool型のprvalueに変換できます。ゼロ値、nullポインター値、またはnullメンバーポインター値はfalseに変換されます。その他の値はすべてtrueに変換されます。直接初期化(8.5)では、タイプstd :: nullptr_tのprvalueをタイプboolのprvalueに変換できます。結果の値はfalseです。

さらに、このドラフトドキュメントで整数型への変換が言及されている唯一の場所std::nullptr_tは、「reinterpret_cast」セクションです。

5.2.10キャストの再解釈
...
(4)ポインタは、それを保持するのに十分な大きさの整数型に明示的に変換できます。マッピング関数は実装定義です。[注:基礎となるマシンのアドレス指定構造を知っている人にとっては、当然のことです。—後記] std :: nullptr_t型の値は、整数型に変換できます。この変換の意味と有効性は、(void *)0から整数型への変換と同じです。[注:reinterpret_castを使用して、型の値を型std :: nullptr_tに変換することはできません。—エンドノート]

したがって、これらの2つの観察から、コンパイラーが正しいと合理的に推測することができます(IMHO)MSVC

編集:ただし、「関数表記キャスト」を使用すると、実際には反対が示唆される場合があります。MSVCコンパイラは、例えば、でCスタイルのキャストを使用して問題ありません。

uintptr_t answer = (uintptr_t)(nullptr);

しかし(あなたのコードのように)、これについて不満があります:

uintptr_t answer = uintptr_t(nullptr); // error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'uintptr_t'

しかし、同じドラフト標準から:

5.2.3明示的な型変換(関数表記)
(1)単純型指定子(7.1.6.2)または型名指定子(14.6)とそれに続く括弧で囲まれた式リストは、指定された型の値を、式リストを指定して構成します。式リストが単一の式である場合、型変換式は対応するキャスト式(5.4)と(定義上、意味で定義されている場合)同等です。...

「対応するキャスト式(5.4)」はC形式のキャストを参照できます。


0

すべて標準に準拠しています(C ++のドラフトn4659を参照)。

nullptr [lex.nullptr]で次のように定義されています:

ポインターリテラルは、キーワードnullptrです。これは、タイプstd :: nullptr_tのprvalueです。[注:...、このタイプのprvalueはnullポインター定数であり、nullポインター値またはnullメンバーポインター値に変換できます。]

ノートが非規範的である場合でも、これにより、標準でnullptrは、null ポインター値に変換されることが期待されます。

後で[conv.ptr]で見つけます:

NULLポインター定数は、値がゼロの整数リテラル、またはstd :: nullptr_tタイプのprvalueです。nullポインター定数はポインター型に変換できます。....整数型のnullポインタ定数は、std :: nullptr_t型のprvalueに変換できます。

ここでも何規格で要求されることはつまり0に変換することができstd::nullptr_t、それがnullptr任意のポインタ型に変換することができます。

私の見解では、標準は直接整数型に変換nullptrできるかどうかについての要件はありません。その時点から:

  • MSVCには厳密な読み取りがあり、変換を禁止します
  • Clangとgccは、中間void *変換が含まれているかのように動作します。

1
これは間違っていると思います。一部のnullポインター定数は、値がゼロの整数リテラルですnullptrが、整数型ではないため、そうではありませんstd::nullptr_t。0はstd::nullptr_t値に変換できますが、リテラルには変換できませんnullptr。これはすべて意図的なものでstd::nullptr_tあり、意図しない変換を防ぐためにより制限されたタイプです。
MSalters

@MSalters:私はあなたが正しいと思います。私はそれを書き直したかったし、それを間違った。私はあなたのコメントで私の投稿を編集しました。ご協力ありがとうございました。
セルジュバレスタ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.