22

関数があるとしましょう:

template <bool stuff>
inline void doSomething() {
    if(stuff) {
        cout << "Hello" << endl;
    }
    else {
        cout << "Goodbye" << endl;
    }
}

そして、私はそれを次のように呼びます:

doSomething<true>();
doSomething<false>();

それは突き出ます:

Hello
Goodbye

私が本当に疑問に思っているのは、コンパイラがこれを完全に最適化するということですか? テンプレート化された関数を true で呼び出すと、"Hello" だけを出力し、if ステートメントと "さようなら" のコードを回避する関数が作成されますか?

これは、非常に最適化され、不要な if ステートメントのチェックを可能な限り回避するはずの、先ほど書いたこの 1 つの巨大な関数に非常に役立ちます。最適化なしのデバッグ ビルドではないにしても、少なくとも最適化ありのリリース ビルドではそうなるでしょう。

4

5 に答える 5

17

免責事項: 誰も何も保証できません。

とはいえ、これはどのコンパイラにとっても明白で簡単な最適化です。オプティマイザーが実質的に役に立たない場合を除いて、最適化によって取り除かれると言っても過言ではありません。

「true」と「false」は定数であるため、各クラスで明らかなデッドブランチを明確に作成しており、コンパイラはそれを最適化する必要があります。ここでは文字通りに取るべきです - 「最適化」コンパイラがデッドブランチの削除を行わなかった場合、それは大きな、大きな問題だと思います。

言い換えれば、コンパイラがこれを最適化できない場合、評価する必要があるのはそのコンパイラの使用であり、コードではありません。

したがって、あなたの直感は正しいと言えます。はい、すべてのコンパイラーでそのような「保証」を行うことはできませんが、生産環境で単純な最適化を実行できないコンパイラーは使用しません。パフォーマンスが重要なもの。(もちろんリリースビルドで)。

だから、それを使用してください。これは単純な最適化であるため、最新の最適化コンパイラーはそれを最適化して取り除きます。疑わしい場合は、逆アセンブルを確認し、最適化されていない場合は、コンパイラを最新のものに変更してください。

一般に、パフォーマンスが重要なコードを作成する場合は、少なくともある程度はコンパイラの最適化に依存する必要があります。

于 2012-08-25T12:13:29.770 に答える
3

これは本質的にコンパイラ次第であるため、コンパイラのドキュメントまたは生成されたコードを確認する必要があります。ただし、このような単純なケースでは、最適化を自分で簡単に実装できます。

template <bool stuff>
inline void doSomething();

template<>
inline void doSomething<true>() {
    cout << "Hello" << endl;
}

template<>
inline void doSomething<false>() {
    cout << "Goodbye" << endl;
}

しかし、「最適化」は実際にパフォーマンスを低下させる可能性があるため、実際に使用するのに適切な言葉ではありません。コードのパフォーマンスが実際に向上する場合は、最適化にすぎません。

于 2012-08-19T22:40:29.350 に答える
1

コンパイラは定数畳み込みが本当に得意です。つまり、この場合、最適化が完了するまでチェックが維持されるとしたら、私は驚きます。最適化されていないビルドでもチェックが行われる可能性があります。確認する最も簡単な方法は、アセンブラー出力を作成して確認することです。

とは言うものの、コンパイラが1つのブランチしか使用しない場合でも、コンパイラが両方のブランチが正しいかどうかをチェックする必要があることに注意してください。これは、たとえば、ランダムアクセスイテレータと他のイテレータにわずかに異なるアルゴリズムを使用している場合に頻繁に発生します。条件はタイプ特性に依存し、特性によってテストされた操作によっては、ブランチの1つがコンパイルに失敗する場合があります。委員会は、コンセンサスがない場合でも、機能が正確にどのように見えるか(追加された場合)について、静的という用語でこのチェックをオフにすることを検討しました。

于 2012-08-19T23:01:13.393 に答える
1

確かに、それは実際には 2 つの関数を作成しますが、

時期尚早の最適化は諸悪の根源

特に、単純な if ステートメントのためにコード構造を変更する場合。これがパフォーマンスに影響を与えるとは思えません。また、ブール値は静的でなければなりません。つまり、実行時に評価された変数を取得して関数に渡すことはできません。リンカーはどの関数を呼び出すかをどのように知る必要がありますか? この場合、手動で評価し、適切な関数を自分で呼び出す必要があります。

于 2012-08-19T22:37:13.230 に答える
0

私があなたを正しく理解していれば、(本質的に) true または false のいずれかの入力に対して最適化された「2つの」関数になり、そのフラグをチェックする必要がなくなりますか?

生成される可能性のある些細な最適化は別として(私は時期尚早の最適化に反対しています-最適化の前に測定前の保守性を信じています)、関数を実際に2つの関数にリファクタリングしてみませんか?共通のコードがある場合は、そのコードもリファクタリングできます。ただし、リファクタリングが最適ではないような要件がある場合は、それを #define リファクタリングに置き換えます。

于 2012-08-19T22:37:24.633 に答える