GCC9はすでに_std::is_constant_evaluated
_を実装しています。少し遊んでみて、ややトリッキーだと気づきました。これが私のテストです:
_constexpr int Fn1()
{
if constexpr (std::is_constant_evaluated())
return 0;
else
return 1;
}
constexpr int Fn2()
{
if (std::is_constant_evaluated())
return 0;
else
return 1;
}
int main()
{
constexpr int test1 = Fn1(); // Evaluates to 0
int test2 = Fn1(); // Evaluates to 0
int const test3 = Fn1(); // Evaluates to 0
constexpr int test4 = Fn2(); // Evaluates to 0
int test5 = Fn2(); // Evaluates to 1
int const test6 = Fn2(); // Evaluates to 0
}
_
これらの結果から、次の結論を導き出しました。
if constexpr (std::is_constant_evaluated())
は常にtrue
ブランチを評価します。したがって、この構造を使用しても意味がありません。
コンパイラがコンパイル時に変数を評価する場合、std::is_constant_evaluated())
は、その変数に明示的にtrue
と注釈が付けられているかどうかに関係なく、constexpr
です。
私は正しいですか?
if constexpr
には、条件に定数式が必要です。そう is_constant_evaluated
はもちろん、そのようなコンテキストでは常にtrueになります。
通常のif
用です。目的は、定数式で評価されるときにconstexpr
関数で不正なコードパスに入らないようにすることです。しかし、実行時に実行させるには。これらのコードパスを関数から完全に削除することはありません。
これが私がこれについて考える方法です、多分あなたはこれが役立つと思うかもしれません...多分役に立たないでしょう。 if constexpr (std::is_constant_evaluated())
を書くことは非常に一般的なエラーになると私は思います、そしてそれは陥りやすいトラップです。しかし、うまくいけば、コンパイラはそのケースを診断するだけです。提出済み 91428 、これはgcc 10.1で修正されています。
基本的に、コードには2つの異なるルールがあります。通常のランタイムコードの一般的なルールと、constexpr
プログラミング用の定数式の制限です。これらはexpr.constの制限です。UBなし、_reinterpret_cast
_などはありません。これらの制限は、言語標準から言語標準に減少し続けています。
基本的に、(コードパスの観点からの)制御フローは、「フルランタイム」モードとconstexpr
モードの切り替えです。 constexpr
モードに入ると(constexpr
オブジェクトを初期化するか、テンプレートパラメータを評価するかによって...)、完了するまでそこに留まります...フルランタイムモードに戻ります。
is_constant_evaluated()
は何をしているのですか?私はconstexprモードですか?定数式を必要とするコンテキストを使用しているかどうかを示します。
そのビューで、if constexpr (is_constant_evaluated())
を見てみましょう。以前使用していた状態に関係なく、_if constexpr
_は初期化時に定数式を必要とするため、これがないとconstexprモードになります。したがって、is_constant_evaluated()
は無条件にtrueになります。
ただし、if (is_constant_evaluated())
の場合、単純なif
はランタイムとconstexprの間で状態を変更しません。したがって、ここでの値は、呼び出し元のコンテキストによって異なります。 _test4
_を初期化すると、constexprオブジェクトであるため、constexprモードになります。初期化の間、定数式の規則に従います... is_constant_evaluated()
はtrueです。しかし、完了したらランタイムルールに戻ります...したがって、_test5
_の初期化では、is_constant_evaluated()
はfalseです。 (そして、_test6
_は不幸な言語の特別なケースです-定数積分変数を定数式として使用できるため、これらの目的のためにそれらの初期化を同じように扱います。)