为什么编译器可以比普通函数更好地优化 lambdas? [英] Why can lambdas be better optimized by the compiler than plain functions?

查看:22
本文介绍了为什么编译器可以比普通函数更好地优化 lambdas?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在他的书中 The C++ Standard Library (Second Edition) Nicolai Josuttis 指出,与普通函数相比,编译器可以更好地优化 lambda.

In his book The C++ Standard Library (Second Edition) Nicolai Josuttis states that lambdas can be better optimized by the compiler than plain functions.

此外,C++ 编译器比它们更好地优化了 lambda普通功能.(第 213 页)

In addition, C++ compilers optimize lambdas better than they do ordinary functions. (Page 213)

这是为什么?

我认为内联应该不再有任何区别.我能想到的唯一原因是编译器可能有更好的 lambda 本地上下文,这样可以做出更多假设并执行更多优化.

I thought when it comes to inlining there shouldn't be any difference any more. The only reason I could think of is that compilers might have a better local context with lambdas and such can make more assumptions and perform more optimizations.

推荐答案

原因是 lambda 是函数对象,因此将它们传递给函数模板将实例化一个专门用于该对象的新函数.因此,编译器可以轻松地内联 lambda 调用.

The reason is that lambdas are function objects so passing them to a function template will instantiate a new function specifically for that object. The compiler can thus trivially inline the lambda call.

另一方面,对于函数,旧的警告适用:函数指针被传递给函数模板,并且编译器传统上有很多问题通过函数指针内联调用.它们理论上可以被内联,但前提是周围的函数也被内联.

For functions, on the other hand, the old caveat applies: a function pointer gets passed to the function template, and compilers traditionally have a lot of problems inlining calls via function pointers. They can theoretically be inlined, but only if the surrounding function is inlined as well.

例如,考虑以下函数模板:

As an example, consider the following function template:

template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
    for (; begin != end; ++begin)
        *begin = f(*begin);
}

像这样用 lambda 调用它:

Calling it with a lambda like this:

int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });

此实例化的结果(由编译器创建):

Results in this instantiation (created by the compiler):

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 () 并且可以简单地内联对它的调用.(并且使用 any 其他 lambda 调用函数 map 将创建 map 的新实例,因为每个 lambda 都有不同的类型.)

… the compiler knows _some_lambda_type::operator () and can inline calls to it trivially. (And invoking the function map with any other lambda would create a new instantiation of map since each lambda has a distinct type.)

但是当使用函数指针调用时,实例化如下所示:

But when called with a function pointer, the instantiation looks as follows:

template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
    for (; begin != end; ++begin)
        *begin = f(*begin);
}

... 这里的 f 为每次调用 map 指向不同的地址,因此编译器不能内联对 f 的调用,除非周围有对 map 的调用也被内联,以便编译器可以将 f 解析为一个特定的函数.

… and here f points to a different address for each call to map and thus the compiler cannot inline calls to f unless the surrounding call to map has also been inlined so that the compiler can resolve f to one specific function.

这篇关于为什么编译器可以比普通函数更好地优化 lambdas?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆