35

一定の整数値に初期化された constexpr ポインターを宣言しようとしていますが、clang は私の試みをすべて失敗させています。

試行 1:

constexpr int* x = reinterpret_cast<int*>(0xFF);

test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression

試行 2:

constexpr int* x = (int*)0xFF;

test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression

試行 3:

constexpr int* x = (int*)0 + 0xFF;

test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer

私がやろうとしていることは、設計上許可されていませんか? もしそうなら、なぜですか?そうでない場合は、どうすればよいですか?

注: gcc はこれらすべてを受け入れます。

4

2 に答える 2

26

Luc Danton が指摘しているように、あなたの試みは [expr.const]/2 のルールによってブロックされます。これは、次のようなさまざまな式がコア定数式で許可されていないことを示しています。

-- a reinterpret_cast
-- 未定義の動作をする操作 [注: [...] 特定のポインタ演算を含む [...] -- 終わりの注]

最初の箇条書きは、最初の例を除外します。2 番目の例は、上記の最初の箇条書きに加えて、[expr.cast]/4 の次のルールによって除外されます。

[...] a reinterpret_cast[...] によって実行される変換は、明示的な型変換のキャスト表記を使用して実行できます。同じ意味上の制限と動作が適用されます。

2 番目の箇条書きはWG21 コアの問題 1313によって追加され、null ポインターでのポインター演算は定数式では許可されないことを明確にしています。これにより、3 番目の例が除外されます。

これらの制限がコア定数式に適用されなかったとしても、constexpr ポインター変数はアドレス定数式constexprによって初期化する必要があるため、整数をキャストすることによって生成された値でポインターを初期化することはできません。 .const]/3、次のように評価する必要があります

静的ストレージ期間を持つオブジェクトのアドレス、関数のアドレス、または null ポインター値。

ポインター型への整数キャストは、これらのいずれにも当てはまりません。

g++ はまだこれらの規則を厳密に適用していませんが、最近のリリースでは規則に近づいているため、最終的には完全に実装されると想定する必要があります。

静的初期化が実行される変数を宣言することが目標である場合は、単純にドロップできますconstexpr-- clang と g++ の両方が、この式の静的初期化子を発行します。何らかの理由でこの式を定数式の一部にする必要がある場合は、次の 2 つの選択肢があります。

  • ポインターの代わりに intptr_t が渡されるようにコードを再構築し、必要に応じて (定数式の外で) ポインター型にキャストするか、または
  • を使用し__builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFFます。この正確な形式の式 (__builtin_constant_p条件演算子の左側にある) は、条件演算子のアームでの厳密な定数式チェックを無効にし、あまり知られていませんが、文書化された移植性のない GNU 拡張であり、両方でサポートされています。 gccとclang。
于 2012-04-29T22:31:16.530 に答える
5

その理由は、(一度だけ、非常に役立つ) エラー メッセージによって示されるものです: reinterpret_castis not allowed in a constant expression. これは、5.19 (パラグラフ 2) の明示的な例外の 1 つとしてリストされています。

reinterpret_castを C スタイルのキャストに変更しても、意味的には a と同等になるreinterpret_castため、役に立ちません (また、メッセージは非常に明示的です)。

0を持つポインターを取得する方法があれば、実際に使用できますp + 0xffが、定数式でそのようなポインターを取得する方法は考えられません。0null ポインター値 (あなたが行ったようなポインター コンテキスト内、またはnullptr) が実装で値を持つことに依存することもでき0ましたが、実装でそれを拒否していることを見てきたように。そうすることが許されていると思います。(例えば、実装はほとんどの定数式を救済することが許可されています。)

于 2012-04-29T08:47:33.177 に答える