5

ウィンドウ プロシージャの外で、switch次のように、自己実行ラムダを使用してステートメントを作成しています。

LRESULT CALLBACK proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    スイッチ (メッセージ)
    {
        case WM_CREATE: return [&](WPARAM wp, LPARAM lp) {
            do_something(wp, lp);
            0 を返します。
        }(wp、lp);

        case WM_SIZE: return [&](HWND hWnd) {
            do_another_thing(hWnd);
            0 を返します。
        }(hWnd);
    }
    return DefWindowProc(hWnd, msg, wp, lp);
}

コンパイラーは自由に最適化できると思いますが、一般的に言えば、これらのラムダを使用しない場合と比較して、コンパイラーはこれに多くの定型コードを追加しますか?

コンパイラは冗長なラムダを検出して削除できますか?

4

2 に答える 2

7

このような最適化の質問には、準拠したコンパイラのオプティマイザが非常に多くのことを実行できるという意味で、明確な答えはありません。ただし、この場合、ほとんどの最新のオプティマイザーはほぼ確実にラムダをインライン化し、ラムダを使用するかどうかに関係なく同じアセンブリを生成します。ラムダには一意の型があるため、コンパイラ簡単にインライン化できます。ラムダは宣言され、すぐに使用され、割り当てられることはないため (より一般的な名前は、「自己実行」ではなく「すぐに呼び出される/評価されるラムダ」です)、コンパイラは、一度しか呼び出せないことを認識しています。したがって、通常はインライン化することを決定します。

確かに、いくつかのアセンブリを見ることができます: https://godbolt.org/g/QF6WmR。ご覧のとおり、この特定の例で生成されたアセンブリは同一ですが、明らかに一般的なケースを証明していません。

一般に、ラムダは C++ では低コストまたはゼロ コストの抽象化と見なされます。ラムダが最もクリーンなコードになると思われる場合は、ラムダを使用してください。必要に応じて、アセンブリが同じであることをいつでもすばやく確認できます。ただし、ラムダをそのように使用する理由は少し珍しいです。コードの折りたたみが正当な理由であるとは、私は本当に考えていません。すぐに評価されるラムダを使用するより一般的な理由は、他の方法では使用constできない状況で使用できるようにすることです。

int x;
try {
    x = foo();
}
catch (const ExceptionType& e) {
    x = bar();
} 

const auto x = [] () {
    try {
        return foo();
    }
    catch (const ExceptionType& e) {
        return bar();
    }
}();

x従来の C++ コードで外側のスコープに永続化するには、最初に宣言してから代入する必要があります。必要な値を返すラムダを使用することxで、宣言と代入を同時に行うことができ、const.

于 2016-10-05T02:15:02.320 に答える
5

質問は少し奇妙です。ラムダはソース コードにあり、コンパイラはソース コードを変更しないため、コンパイラはラムダを「削除」しません。ソースコードで表現したプログラムの動作を生成するマシンコードを出力します。

コンパイラは、結果がプログラムの表現どおりに動作する限り、好きなだけマシン コードを自由に発行できます。

コンパイラは、すべてのコードを 1 か所にインライン化できる場合、個別の関数本体とそれらの間のジャンプ/呼び出しを発行する必要はありません。これは、一般的に適用される最適化です。

于 2016-10-04T23:39:03.643 に答える