62

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

例:

  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の関数が宣言されないのはなぜですか?(まだ十分な時間がなかったため、まだ完了していないと主張することはできません。すべての機能を実行するのは簡単です。すべての機能を実行するかどうかを決定するのとは対照的です。)- --N2976は、コンテナなどの多くの標準ライブラリタイプにcstrを意図的に必要としないことを認識しています。これは、可能な実装には制限が多すぎるためです。それらを引数から除外して、疑問に思います。標準ライブラリの型に実際にcstrが含まれていると、それを操作するすべての関数が宣言されないのはなぜですか。constexprconstexprconstexprconstexpr

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

だから私は、関数を故意に宣言しないための正当な理由と良い例があるに違いないと思いますconstexprか?

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

質問なぜstd::forward捨てるのconstexprか?これの特殊なケースです。

4

3 に答える 3

37

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

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

まず、これはとして実装できる各機能をチェックする必要がありconstexpr、これは長い仕事です。

第二に、これは実装に対する大きな制約であり、多くのデバッグ実装を非合法化します。したがって、利点がコストを上回る場合、または要件が十分に厳しく、実装がconstexprルールにほとんど従わなければならない場合にのみ、価値があります。このように関数ごとに評価を行うのは、やはり長い仕事です。

于 2011-02-25T10:59:16.653 に答える
15

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

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

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

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

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

お役に立てれば!

于 2011-02-25T04:29:42.130 に答える
4

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

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

于 2011-02-25T05:15:41.877 に答える