为什么lambda可以通过编译器比普通函数更好地优化?

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

另外,C ++编译器比普通函数更好地优化lambda表达式。 (页213)

这是为什么?

我认为当谈到内联时,应该没有任何区别了。 我能想到的唯一原因是编译器可能对lambda表达式有更好的本地环境,这样可以做出更多的假设并执行更多的优化。


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

另一方面,对于函数,旧的注意事项适用:函数指针传递给函数模板,编译器通过函数指针传入内联函数时会遇到很多问题。 理论上讲,它们可以内联,但前提是内联函数也是内联的。

作为一个例子,考虑下面的函数模板:

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 ()并且可以内联地调用它。 (并且用任何其他lambda调用函数map会创建一个新的map实例,因为每个lambda具有不同的类型。)

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

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解析为一个特定函数。


因为当你向算法传递一个“函数”时,你实际上传递了一个指向函数的指针,所以它必须通过指向该函数的指针进行间接调用。 当你使用一个lambda表达式时,你将一个对象传递给一个专门为该类型实例化的模板实例,并且对lambda函数的调用是直接调用,而不是通过函数指针调用,因此可能更有可能被内联。

链接地址: http://www.djcxy.com/p/85707.html

上一篇: Why can lambdas be better optimized by the compiler than plain functions?

下一篇: Why would I ever use push