web-dev-qa-db-ja.com

関数を `constexpr`であると**宣言**しないのはなぜですか?

Returnステートメントのみで構成される関数はconstexprとして宣言できるため、すべての引数がconstexprであり、constexpr関数のみが呼び出される場合、コンパイル時に評価できます。その体。 宣言しない理由はありますかanyそのような関数constexpr

例:

  constexpr int sum(int x, int y) { return x + y; }
  constexpr i = 10;
  static_assert(sum(i, 13) == 23, "sum correct");

関数constexprを宣言すると害が生じる例を誰かが提供できますか?


いくつかの最初の考え:

constexprではない関数を宣言する正当な理由がない場合でも、constexprキーワードが過渡的な役割を持っていると想像できます。コンパイル時の評価を必要としないコードが存在しないと、コンパイル時の評価を実装していないコンパイラーがそのコードをコンパイルできるようにします(ただし、constexprを使用して明示的に行う必要があるコードでは確実に失敗します)。

しかし、私が理解していないこと:constexprではない関数を宣言する正当な理由がない場合、なぜevery関数ではないのかconstexprと宣言された標準ライブラリでは? (allを実行するのは非常に簡単であるため、実行するのに十分な時間がなかったため、まだ実行されていないと主張することはできません-すべての決定とは逆にconstexprにするかどうかに応じて単一の関数にします。)---私は N2976 が意図的にコンテナなどの多くの標準ライブラリタイプのcstrsを必要としないことを認識しています。可能な実装。それらを引数から除外してみましょう:標準ライブラリの型が実際にconstexpr cstrを持つと、その関数で動作するすべての関数がconstexprと宣言されないのはなぜですか?

ほとんどの場合、コンパイル時の使用を想定していないという理由だけで関数constexprを宣言しないほうがよいと主張することもできません。あなたのコードを使用しますが、彼らはあなたがそうではないそのような使用を見るかもしれません。 (もちろん、タイプ特性タイプなどについては当然認められます。)

関数constexprを故意に宣言しないことには、正当な理由と適切な例があるはずだと思います。

(「すべての関数」とは常に意味します:constexprであるための要件を満たすすべての関数、つまり単一のreturnステートメントとして定義され、constexpr cstrsを持つ型の引数のみを取り、constexpr関数。C++ 14以降、 このような関数の本体ではさらに多くのことが許可されています :たとえば、C++ 14 constexpr関数はローカル変数とループを使用できますなので、さらに広いクラスの関数をconstexprと宣言できます。)

質問 なぜstd::forward破棄constexpr- ness? はこれの特殊なケースです。

59
Lars

関数は、constexprの規則に従う場合にのみconstexprと宣言できます---動的キャストなし、メモリ割り当てなし、非constexpr関数の呼び出しなしなど。

標準ライブラリの関数をconstexprとして宣言するには、すべての実装がこれらの規則に従う必要があります。

まず、これには各関数をチェックする必要がありますcanconstexprとして実装されていること、これは長い仕事です。

次に、これは実装に対する大きな制約であり、多くのデバッグ実装を禁止します。したがって、メリットがコストを上回る場合、または要件が十分にタイトで、実装がほとんどconstexprルールに従う必要がある場合にのみ価値があります。各関数に対してこの評価を行うことは、やはり長い仕事です。

34

あなたが言及しているものは 部分評価 と呼ばれていると思います。あなたが触れていることは、いくつかのプログラムは2つの部分に分けることができるということです-ランタイム情報を必要とする部分とランタイム情報なしで実行できる部分-そして理論的にはプログラムの部分を完全に評価することができますプログラムの実行を開始する前に、ランタイム情報は必要ありません。これを行うプログラミング言語がいくつかあります。たとえば、Dプログラミング言語には、コンパイラに組み込まれたインタープリターがあり、特定の制限を満たしていれば、コンパイル時にコードを実行できます。

部分評価を機能させるには、いくつかの主な課題があります。第一に、コンパイラーは、コンパイル時に実行可能プログラムに入れることができるすべての操作をシミュレートする機能を持つ必要があるため、コンパイラーのロジックを劇的に複雑にします。最悪の場合、これにはコンパイラー内に完全なインタープリターが必要であり、困難な問題(優れたC++コンパイラーの作成)が発生し、桁違いに困難になります。

constexprに関する現在の仕様の理由は、単にコンパイラの複雑さを制限するためだと思います。それが限定されているケースは、チェックするのがかなり簡単です。コンパイラーにループを実装する必要はありません(コンパイラー内で無限ループが発生した場合に発生するような、他の多くの問題を引き起こす可能性があります)。また、コンパイラが実行時に、不正なポインタを追跡するなど、segfaultを引き起こす可能性のあるステートメントを評価する必要がないようにします。

留意すべきもう1つの考慮事項は、cinからの読み取りやネットワーク接続のオープンなど、一部の関数には副作用があることです。このような関数は基本的にコンパイル時に最適化できません。これを行うには、実行時にのみ利用できる知識が必要になるためです。

要約すると、C++プログラムをコンパイル時に部分的に評価できなかった理論上の理由はありません。実際、人々はいつもこれをしています。たとえば、最適化コンパイラは、本質的にこれを可能な限り実行しようとするプログラムです。テンプレートメタプログラミングは、C++プログラマーがコンパイラー内でコードを実行しようとする1つのインスタンスです。また、テンプレートのルールが関数型言語を形成し、コンパイラーがより簡単に実装できるため、テンプレートを使用していくつかの素晴らしいことを行うことができます。さらに、コンパイラー作成者の時間とプログラミング時間の間のトレードオフを考えると、テンプレートメタプログラミングは、プログラマーが逆方向に曲がって望みのものを得ることを許可しても、かなり弱い言語(テンプレートシステム)を構築して維持できることを示しています。言語の複雑さは単純です。 (計算能力理論の意味での「弱い」ではなく、「特に表現力がない」のように「弱い」と言います)。

お役に立てれば!

14
templatetypedef

関数に副作用がある場合、constexprとマークしたくないでしょう。

私はそれから予期しない結果を得ることができません、実際には gcc 4.5.1はconstexpr を無視するように見えます

3
Ben Voigt