プレーン関数と比較して、ラムダが強化されたコンパイラ最適化を可能にする理由
Nicolai Josuttis による C 標準ライブラリ (第 2 版) では、ラムダは次のことができると主張しています。単純な関数と比較して、コンパイラによってより効果的に最適化されます。この利点は、関数オブジェクトとしてのラムダの性質に由来します。
ラムダが関数テンプレートに渡されると、そのオブジェクトに合わせて特別に調整された新しい関数としてインスタンス化されます。これにより、コンパイラーはラムダ呼び出しを簡単にインライン化できるようになります。逆に、プレーン関数では、関数ポインタが関数テンプレートに渡されます。従来、コンパイラーは、関数ポインターを介して行われる呼び出しをインライン展開するのが困難でした。
この概念を説明するために、次の関数テンプレートを考えてみましょう:
template <typename Iter, typename F> void map(Iter begin, Iter end, F f) { for (; begin != end; ++begin) *begin = f(*begin); }
ラムダを使用してこの関数を呼び出す:
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() にアクセスでき、それに対する呼び出しをシームレスにインライン化できます。各ラムダには個別の型があるため、map() で異なるラムダを使用すると、新しいインスタンス化が生成されます。
ただし、代わりに関数ポインターが使用された場合は、次のようになります。
map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) { for (; begin != end; ++begin) *begin = f(*begin); }
コンパイラは、包括的な map() への呼び出しもインライン化され、特定の関数を正確に指定できるようになるまで、 f への呼び出しをインライン化することはできません。これは、コンパイラの最適化という点で、プレーン関数よりもラムダの利点を強調しています。
以上がC の単純な関数よりもラムダが最適化されやすいのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。