短い答えは、static
が有用であるだけでなく、いつも望ましいことです。
最初に、static
とconstexpr
は互いに完全に独立していることに注意してください。 static
は、実行中のオブジェクトの存続期間を定義します。 constexpr
は、コンパイル時にオブジェクトを使用できるように指定します。コンパイルと実行は時間と空間の両方で不連続で不連続です。したがって、プログラムがコンパイルされると、constexpr
はもはや関係しません。
すべての変数がconstexpr
を宣言し、暗黙的にconst
ですがconst
とstatic
(static const
整数との相互作用を除く。)はほぼ直交している
C++
オブジェクトモデル(§ 1.9)は、ビットフィールド以外のすべてのオブジェクトが占めることが必要です少なくとも1バイトのメモリとアドレスを有する。さらに、与えられた瞬間にプログラム内で観測可能なすべてのオブジェクトは、別個のアドレスを持たなければならない(パラグラフ6)。これは、ローカル非静的const配列を持つ関数を呼び出すたびにスタック上に新しい配列を作成するコンパイラを必要としません。なぜなら、コンパイラはas-if
の原理で避けている可能性があるからです。観察される。
残念なことに、関数が自明でない限り(たとえば、翻訳単位内でボディが見えない他の関数を呼び出さない限り)、配列は多かれ少なかれ定義されているため、アドレスです。だから、ほとんどの場合、非静的配列はすべての呼び出し時にスタック上で再作成されなければならず、コンパイル時にそれを計算することができなくなります。
一方、ローカルのstatic const
オブジェクトはすべてのオブザーバによって共有され、定義されている関数が呼び出されない場合でも初期化されます。したがって、上記のどれも適用されず、コンパイラーはそのインスタンスを1つだけ生成するだけでなく、読み取り専用ストレージでは、そのインスタンスを1つだけ生成することは自由です。
この例では、間違いなくstatic constexpr
を使用してください。
ただし、static constexper
を使用しない場合があります。 constexpr
宣言されたオブジェクトがODRが使用されているか、またはstatic
と宣言されていない限り、コンパイラは自由にそれを含めません。これは、コンパイル時に不要なバイトを含むプログラムを汚染することなく、コンパイル時にconstexpr
の一時的な配列を使用できるので、非常に便利です。その場合、static
は実行時にオブジェクトを強制的に実行する可能性が高いため、明確にstatic
を使用することは望ましくありません。
'constexpr'はコンパイル時に何も保証しませんが、コンパイラは実行時に' constexpr'を評価することは自由です。コンパイル時に何かを評価しなければならないのは、コンパイル時に知っておく必要があるコンテキストで何かを使用すれば、それだけです。 – Praetorian
私は@Praetorianが正しいと信じていて、 'static'はコンパイル時だけでなく、コンパイル時定数とともに格納されることを保証します。私は '静的'なしに、関数の呼び出しごとに(巨大な)配列をスタックにプッシュすることに理論的に合致すると思います。 –
@AndrewLazarusは、理論的にはすべての呼び出し時にスタックに配列をプッシュすることに理論的に準拠しているだけでなく、理論的には必要です(as-ifルールをモジュロにします)。実際には、私の経験では、それは常によく起こります。詳細は私の答えを見てください。 – rici