22

私は正しいですか:

  • constexprで定義された関数はすべて純粋な関数であり、
  • constexprコンパイラにとって非常に高価でない場合、任意の純粋な関数を定義することができ、定義する必要があります。

もしそうなら、なぜ arent<cmath>の関数が で定義されているのconstexprでしょうか?

4

4 に答える 4

18

他の人が言ったことに追加するには、次のconstexpr関数テンプレートを検討してください。

template <typename T>
constexpr T add(T x, T y) { return x + y; }

このconstexpr関数テンプレートは、場合によっては定数式で使用できますが (例: where Tis int)、他の場合 (例: where isは宣言されていないオーバーロードをT持つクラス型) では使用できません。 operator+constexpr

constexpr関数が定数式で常に使用できるという意味ではなく、関数が定数式で使用できる可能性があることを意味します。

(非テンプレート関数を含む同様の例があります。)

于 2011-03-28T17:09:22.140 に答える
10

前の回答に加えて、関数の constexpr はその実装を大幅に制限します。その本体はコンパイラ (インライン) から見える必要があり、単一の return ステートメントのみで構成されている必要があります。sqrt() または sin() を正しく実装して、最後の条件を満たしているとしたら、私は驚きます。

于 2011-03-28T17:29:09.370 に答える
8

constexpr関数は、引数が定数であり、これらの引数について関数の本体で言及されている操作自体がである場合、コンパイル中に関数が計算される可能性があるというコンパイラへのヒントであるpureためではありません。constexprconstexpr

後者は、テンプレートコードを使用して、不純なconstexpr関数を示すことができます。

template <typename T>
constexpr T add(T lhs, T rhs) { return lhs + rhs; }

このタイプでインスタンス化

DebugInteger operator+(DebugInteger lhs, DebugInteger rhs) {
  printf("operator+ %i %i", lhs._value, rhs._value);
  return DebugInteger(lhs._value + rhs._value);
}

ここでは、operator+はconstexprではないため、グローバル状態の読み取り/書き込みが可能です。

constexpr関数はコンパイル時に評価されると言うことができますpure...しかし、実行時間に関する限り、関数は単に定数に置き換えられます。

于 2011-03-28T19:35:43.493 に答える
-1

すべてのconstexpr関数は純粋ですが、すべての純粋関数が であるわけではありませんconstexpr

[constexpr関数テンプレートを含む例は誤解を招きます。関数テンプレートは関数ではなく、コンパイラが関数を生成できるパターンであるためです。関数テンプレートの結果、その特殊化関数であり、可能性は低いでしょconstexpr。]

純粋関数とは、その引数またはその他の定数状態のみに依存する関数です。それはほとんどconstexpr関数です。さらに、constexpr関数は最初に使用する前に (宣言するだけでなく) 定義する必要があり (ただし、再帰は許可されているようです)、return ステートメントのみで構成する必要があります。これは、許可されたサブセットをチューリング完全にするのに十分ですが、実行時に必ずしも結果が最も効率的な形式になるとは限りません。

これにより、数学関数が表示されます。おそらくconstexpr sqrt()orsin()を実装できますが、コンパイラがコンパイル時に評価できる再帰的な実装を使用する必要がありますが、実行時には、これらは 1 つのアセンブラー操作で実装する方が適切です。とconstexprの使用はほとんどなく、かなり離れているため、代わりに実行時のパフォーマンスを最大化することをお勧めします。これには、実行できないフォームが必要です。sqrt()sin()constexpr

関数の1 つのバージョンと実行時に使用されるバージョンを作成できないのはなぜかと思うかもしれません。constexprそれがあればいいのですが、標準では、constexprness をオーバーロードできないと書かれています。おそらくC++ 17で...

于 2012-06-15T15:20:46.340 に答える