小编典典

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

all

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

此外,C++ 编译器比普通函数更能优化 lambda。(第 213 页)

这是为什么?

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


阅读 152

收藏
2022-07-28

共1个答案

小编典典

原因是 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 ()并且可以简单地内联对它的调用。map(并且使用 任何 其他
lambda调用该函数将创建一个新的实例化 ,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到一个特定的函数。

2022-07-28