web-dev-qa-db-ja.com

std :: is_constant_evaluatedの動作

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です。

私は正しいですか?

19
metalfox

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_は不幸な言語の特別なケースです-定数積分変数を定数式として使用できるため、これらの目的のためにそれらの初期化を同じように扱います。)

13
Barry