ラムダはコンパイラによって単純な関数よりも最適化できますか?

Mary-Kate Olsen
リリース: 2024-11-19 18:33:03
オリジナル
200 人が閲覧しました

Can Lambdas Be Optimized Better Than Plain Functions By Compilers?

ラムダのコンパイラ最適化とプレーン関数

Nicolai Josuttis は、著書「The C Standard Library (Second Edition)」の中で次のように主張しています。ラムダは単純な関数よりもコンパイラによって最適化できるということです。ラムダ関数とプレーン関数の両方をインライン化できることを考えると、これは直観に反するように思えるかもしれません。ただし、この 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);
}
ログイン後にコピー

コンパイラはラムダの Operator() を識別し、それに対する簡単なインライン呼び出しを行うことができます。

しかし、関数ポインタを使用して呼び出された場合:

map(begin(a), end(a), &multiply_by_two);
ログイン後にコピー

インスタンス化は次のようになります:

template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
    for (; begin != end; ++begin)
        *begin = f(*begin);
}
ログイン後にコピー

ここで、f はマップが呼び出されるたびに異なる関数を参照するため、マップが呼び出されるたびに異なる関数が参照されます。

結論

関数オブジェクトとしての独自のタイプのラムダにより、コンパイラは特定の関数のインスタンス化を作成し、その呼び出しをシームレスにインライン化できます。この強化された最適化機能により、ラムダは単純な関数と区別され、コードのパフォーマンスと効率を向上させるための好ましい選択肢となります。

以上がラムダはコンパイラによって単純な関数よりも最適化できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート