ラムダ関数の最適化
Nicolai Josuttis は、「The C Standard Library」の中で、コンパイラーは単純な関数よりもラムダを最適化すると主張しています。これは、なぜそうなるのかという疑問を引き起こします。
インライン最適化
インライン最適化ではラムダ関数とプレーン関数が区別されないと考える人もいるかもしれません。ただし、重要な違いは、関数オブジェクトとしてのラムダの性質にあります。
関数オブジェクトと関数ポインター
ラムダが関数テンプレートに渡されると、は、そのオブジェクト専用の新しい関数を作成し、その結果、簡単にインライン化可能な関数呼び出しが行われます。対照的に、プレーン関数は関数ポインターを渡すため、通常はインライン最適化で問題が発生します。コンパイラは理論的にはそのような呼び出しをインライン化できますが、それは周囲の関数もインライン化されている場合に限られます。
例
イテレータと関数オブジェクトを次のように受け取る関数テンプレート マップを考えてみましょう。パラメータ:
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); }
コンパイラはラムダの演算子()への呼び出しを簡単にインライン化できます。
ただし、関数ポインタを使用する:
int a[] = { 1, 2, 3, 4 }; map(begin(a), end(a), &my_function);
結果のインスタンス化
template <> void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) { for (; begin != end; ++begin) *begin = f(*begin); }
ここで、f はマップの呼び出しごとに異なるアドレスを指し、周囲のマップの呼び出しもインライン化されない限りインライン最適化を禁止します。
したがって、次の最適化の利点は次のようになります。ラムダは、簡単なインライン機能を可能にする関数オブジェクトを作成する機能に由来しています。
以上がコンパイラが単純な関数よりもラムダを最適化するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。