18

関数(またはコンストラクタ)のためだけに...

  • constexpr と宣言され、
  • 関数定義は constexpr 要件を満たしています

...コンパイラが変換中に constexpr 関数を評価するという意味ではありません。C++11 FDIS (N3242、http: //www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/ で入手可能) を調べて、次の 2 つのことを試してみました。

  • 翻訳中にコンパイラが constexpr 関数を評価する義務があるのはいつですか?
  • 翻訳中にコンパイラが constexpr 関数を評価できるのはいつですか?

セクション 5.19 パラグラフ 1 は、変換中に定数式を評価できると述べています。私が理解できる限り、セクション 5.19 の残りの部分では、constexpr 関数の定義で何が有効かについてのルールを説明しています。

constexpr 関数の結果を constexpr として宣言することで、翻訳中に constexpr の評価を強制できることを理解しています。このような:

// Declaration
constexpr double eulers_num() { return 2.718281828459045235360287471; }

// Forced evaluation during translation
constexpr double twoEulers = eulers_num() * 2.0;
static_assert(twoEulers > 5.0, "Yipes!");

これまでのところ、FDIS で次の段落を見つけることができませんでした。

  • twoEulers翻訳中に評価される力または
  • コンパイラが変換中に constexpr 関数を評価する場合、または評価する必要がある場合のその他の状況を指定します。

私が特に興味を持っているのは、翻訳中の constexpr 評価が以下によってトリガーされるかどうかです。

  1. constexpr 関数に渡されるすべてのパラメーターがリテラルの場合、または
  2. オーバーロード解決中の暗黙のオブジェクト引数(セクション 13.3.1 パラグラフ 3) は、constexpr であるか、リテラル (配列次元など) を必要とするか、または
  3. まったく別の何か。

可能であれば、回答の中で、私が調べられる FDIS のセクションまたは FDIS で検索できるキー フレーズを引用してください。標準の英語はやや鈍いので、関連する段落を読んでいて、その意味や意図を完全に見逃している可能性があります。

4

4 に答える 4

7

constexpr実際に可能な場合はいつでも、コンパイル時に呼び出しを評価することが「許可」されています。仕様は「仮定」ルールの下で動作することに注意してください。したがって、違いがわからない場合は、コンパイラーは何でもできます。

コンパイラは、コンパイル時に実際に応答が必要な場合に、コンパイル時に呼び出しを評価する必要があります。例えば:constexpr

constexpr int foo() {return 5;}

std::array<float, foo()> arr;

コンパイラは、コンパイル時に配列サイズを知る必要があります。したがって、コンパイル時に定数式を評価する必要があります。constexprコンパイル時に関数を実行できない場合、コンパイル時エラーが発生します。

于 2012-11-27T06:18:55.433 に答える
4

Nicol Bolasは100%正しいですが、もう1つの興味深い側面があります。それは、式が翻訳時に評価されるかどうか、および実行時に評価されるかどうかは、完全に独立した質問です。定数式には副作用がないため、任意の回数で評価でき、変換時と実行時の両方で評価を妨げるものはありません。

定数式が大きな配列(ではなくstd::array、単なる配列)であり、これは完全に合法であり、プログラムは静的ストレージがあることを示していないとします。また、コンパイル時の計算が必要なコンテキストで、配列の要素7のみが使用されているとします。コンパイラが配列全体を計算し、要素7を使用して破棄し、計算された配列全体でバイナリを肥大化させるのではなく、実行時に使用されるスコープでコードを挿入して計算することは非常に合理的です。これは理論上の問題ではないと思います。さまざまな状況でさまざまなコンパイラを使用してそれを観察しました。を意味するものでconstexprはありませstatic

もちろん、コンパイラが実行時に配列が使用されていないと判断できる場合、それを計算するためのコードを挿入することさえできないかもしれませんが、それはさらに別の問題です。

実行時にそのようなオブジェクトを使用し、プログラムの期間中はオブジェクトを保持する価値があることをコンパイラーに示したい場合は、として宣言する必要がありますstatic

于 2012-11-27T06:41:11.573 に答える
4

FDIS を組み合わせることで、変換中に constexpr 式を評価する必要がある場所を指定する 3 つの場所を見つけました。

セクション 3.6.2 Initialization of non-local variablesの段落 2 では、静的またはスレッド ローカル ストレージ期間を持つオブジェクトがコンストラクターで初期化されるconstexpr場合、コンストラクターは変換中に評価されると述べています。

一定の初期化が実行されます。

  • 静的またはスレッドのストレージ期間を持つオブジェクトがコンストラクター呼び出しによって初期化される場合、コンストラクターがconstexprコンストラクターである場合、すべてのコンストラクター引数が定数式 (変換を含む) である場合、および関数呼び出し置換 (7.1.5) の後、すべてのコンストラクターがmem-initializersの call と full-expression は定数式です。

セクション 7.1.5 の constexpr 指定子のパラグラフ 9 は、オブジェクト宣言にconstexpr指定子が含まれている場合、そのオブジェクトは変換中に評価される (つまり、リテラルである) と述べています。

constexprオブジェクト宣言で使用される指定子は、オブジェクトを const として宣言します。そのようなオブジェクトはリテラル型を持ち、初期化されます。コンストラクター呼び出しによって初期化される場合、その呼び出しは定数式 (5.19) でなければなりません。それ以外の場合、初期化子に現れるすべての完全式は定数式になります。初期化式の変換に使用される各暗黙的な変換と、初期化に使用される各コンストラクター呼び出しは、定数式 (5.19) で許可されているもののうちの 1 つでなければなりません。

このパラグラフは、たとえばstatic_assert. 変換中に値が初期化されるかどうかは、状況によっては観察可能であるため、これはおそらく正確な見方ではありません。この見解は、セクション 5.19 定数式のパラグラフ 4によって強化されます。

[注:一部のコンテキストでは、プログラムの変換中に定数式を評価する必要がありますが、プログラムの実行中に評価する場合もあります。この国際規格は浮動小数点演算の精度に制限を課していないため、変換中の浮動小数点式の評価が同じ式の評価 (または同じ値に対する同じ演算) と同じ結果をもたらすかどうかは規定されていません。 ) プログラム実行中... —エンドノート]

セクション 9.4.2 静的データ メンバーのパラグラフ 3 は、リテラル型の const 静的データ メンバーが constexpr 関数またはコンストラクターによって初期化される場合、その関数またはコンストラクターは変換中に評価される必要があると述べています。

静的データ メンバーが const リテラル型の場合、クラス定義でのその宣言は、代入式であるすべての初期化子節が定数式であるブレースまたは等号初期化子を指定できます。リテラル型の静的データ メンバーは、指定子を使用してクラス定義で宣言できます。その場合、その宣言は、割り当て式であるすべての初期化子節が定数式であるブレースまたは等号初期化子を指定するものとします。[注:どちらの場合も、メンバーは定数式に現れる場合があります。—エンドノート]constexpr

constexpr興味深いことに、FDIS には、結果が配列次元として使用される場合に式を評価する必要があるものは見つかりませんでした。私は、標準委員会がそうであることを期待していると確信しています。しかし、検索でそれを見逃した可能性もあります。

これらの状況以外では、C++11 標準で、constexpr 関数とコンストラクターでの計算を変換中に実行できます。しかし、それは必要ありません。計算は実行時に発生する可能性があります。翻訳中にコンパイラが実行する計算は、ある程度、実装の品質の問題です。

constexpr私が見つけた 3 つの状況すべてで、翻訳時間評価のトリガーは、呼び出しの結果を使用したターゲットの要件に基づいています。関数の引数がリテラルかどうかconstexprは考慮されません (有効な評価の前提条件ですが)。

したがって、これの本当のポイントに到達するために、constexpr翻訳中の評価は次のようにトリガーされるようです。

  • オーバーロード解決中の暗黙のオブジェクト引数 (セクション 13.3.1 パラグラフ 3) は、constexpr であるか、リテラルが必要です。

私以外の誰かの参考になれば幸いです。貢献してくれたすべての人に感謝します。

于 2012-12-09T02:31:03.890 に答える
1

どこも強制ではないと思います。そのリストには constexpr に関する論文が 1 つもないため、注意が必要です。それらはすべて、以前の論文集に追加/削除されているようです。

一般的な考え方は、constexpr 関数への入力が constexpr 自体である場合、すべてコンパイル時に行われると思います。また、機能を持たない constexpr ステートメントの拡張により、どちらにしてもリテラルであり、ハーフ インテリジェント コンパイラを使用している場合は、コンパイル時に実行されます。

constexpr 関数またはコンストラクターが定数式ではない引数で呼び出された場合、呼び出しは関数が constexpr ではないかのように動作し、結果の値は定数式ではありません。

ウィキペディアから

このpdfから情報を取得しているようです:

constexpr 関数: constexpr 関数は、「十分に単純な」関数であり、定数値である引数で呼び出されたときに定数式を提供します (§2.1 を参照)。

于 2012-11-27T05:58:55.797 に答える