为什么lambda表达式编译器比普通的功能得到更好的优化?(Why can lambdas be b

2019-06-21 15:23发布

在他的书The C++ Standard Library (Second Edition)尼古拉约祖蒂斯指出lambda表达式可以由编译器比普通的功能得到更好的优化。

此外,C ++编译器优化lambda表达式比他们做的普通功能。 (第213页)

这是为什么?

我认为,当涉及到内联不应该有任何区别了。 我能想到的唯一原因是,编译器可能与lambda表达式更好的当地情况和这样可以让更多的假设,并进行更多的优化。

Answer 1:

其原因是,lambda表达式是函数对象 ,以便将它们传递给函数模板将具体实例化一个新的函数,该函数对象。 编译器可以这样平凡的内联拉姆达电话。

对于函数,而另一方面,旧的原则同样适用:一个函数指针被传递给函数模板和编译器传统上有很多通过内联函数指针调用问题。 理论上是可以被内联,但只有当周围的内联函数为好。

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

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因为每个拉姆达具有不同的类型。)

但是,当一个函数指针调用,实例如下所示:

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到一个特定的功能。



Answer 2:

因为当你传递一个“功能”进行运算,你实际上传递函数指针,因此具有通过函数指针做一个间接调用。 当您使用lambda你传递一个对象实例化专门为该类型和调用lambda函数模板实例是直接调用,而不是通过函数指针调用,可以更容易得多内联。



文章来源: Why can lambdas be better optimized by the compiler than plain functions?