constexpr関数について学び、コンパイラがコードを最適化する方法を知るためにgodboltに行き、コンパイラの動作がまったく異なることを発見しました。
次のコードがあります。
constexpr int square(int num) {
return num * num;
}
int main() {
int a = square(2);
}
g ++およびiccコンパイラーは関数の結果を計算し、それを変数に割り当てます(予想どおり)が、msvcおよびclangは関数を呼び出します。
最適化を使用するには、追加の手順を実行する必要があります。
constexpr int square(int num) {
return num * num;
}
int main() {
constexpr int c = square(2);
int a = c;
}
そのような行動の合理的な説明はありますか?
godboltの例へのリンク:https://godbolt.org/z/ez7luu
すべてのコンパイラは正しいです。
constexpr
関数は、状況に応じて、コンパイル時または実行時に計算することができる機能です。
as-ifルールがないふりをすると、コンパイラは、関数の結果が既知のコンパイル時間であることが要求された場所に移動したときに、コンパイル時間を計算する必要があると言えconstexpr
ます。
例として、配列のサイズ
int a[square(10)];
またはテンプレートパラメータ
std::array<int, square(10)> a;
またはconstexpr
変数
constexpr int a { square(10) };
実行時の既知の入力値を受け取る場合のように、関数を実行時に計算する必要がある状況があります。例によって
int a;
std::cin >> a;
int b { square(a) };
それ以外の場合、コンパイラは値をコンパイル時と実行時のどちらで計算するかを選択できます。
あなたの最初のバージョンでは
int a = square(2);
我々はので、コンパイラ-選択することができる領域である2
コンパイラがコンパイル時計算を選択することができますので、コンパイル時に知られているが、値がないため、要求されたconstexpr
コンパイル時の値が必要ではないので、変数。
そして、2つのコンパイラがコンパイル時と他の2つのランタイムを計算していることがわかります。一般に、この種の動作は最適化レベルに大きく依存します。実際、例のコンパイルフラグに追加-O2
した後、すべてのコンパイラは異なる出力を生成します。
2番目のバージョンでは
constexpr int c = square(2);
square()
値が要求されconstexpr
、可変なので、すべてのコンパイラは、しなければならない計算するsquare(2)
(ので、彼らはそれを行うことができますコンパイル時に2
コンパイル時に既知の値です)。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加