ラムダの最適化とインライン関数: コンパイラーの利点
ラムダは単純な関数と比較して優れたコンパイラー最適化を示すという Nicolai Josuttis のステートメントは多くの人の興味をそそりました開発者。この主張を調査し、この最適化の利点の背後にある根本的な理由を解明しようとします。
関数オブジェクトとインライン化
関数オブジェクトであるラムダには、重要な利点があります。関数テンプレートは、そのラムダ専用に調整された関数のインスタンス化をトリガーします。これにより、コンパイラーはラムダ呼び出しを簡単にインライン化できます。
対照的に、関数は関数テンプレートに渡されるときに関数ポインターを使用します。従来、コンパイラは関数ポインタを介した呼び出しをインライン展開する際に課題に直面していました。インライン最適化は、囲んでいる関数自体がインライン化されている場合にのみ実現可能です。
テンプレートのインスタンス化: 違いを調べる
この違いを説明するために、マップ関数テンプレートを考えてみましょう。
template <typename Iter, typename F> void map(Iter begin, Iter end, F f) { for (; begin != end; ++begin) *begin = f(*begin); }
lambda:
int a[] = { 1, 2, 3, 4 }; map(begin(a), end(a), [](int n) { return n * 2; });
は、カスタマイズされたインスタンス化になります:
template <> void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) { for (; begin != end; ++begin) *begin = f.operator()(*begin); }
コンパイラーは _some_lambda_type::operator() 関数を識別し、その関数を直接インライン呼び出しできます。個別のラムダ型ごとにマップの新しいインスタンス化が要求され、ラムダ固有の最適化が保証されます。
対照的に、関数ポインターを使用してマップを呼び出すと、次のインスタンス化が生成されます。
template <> void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) { for (; begin != end; ++begin) *begin = f(*begin); }
ここで、関数はポインタ f はマップ呼び出しごとに異なるアドレスを指し、インライン最適化を禁止します。コンパイラが f を特定の関数に解決するには、map の呼び出しをインライン化する必要があります。
したがって、関数オブジェクトとしてのラムダの特徴と、テンプレートのインスタンス化を容易にする機能により、従来の関数呼び出しよりも優れた最適化機能がコンパイラに与えられます。ポインタを介して。
以上がコンパイラが従来の関数よりも効率的にラムダ関数を最適化するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。