为什么lambda可以比普通函数更好地被编译器优化?
在他的书The C++ Standard Library (Second Edition)
Nicolai Josuttis指出,编译器比普通函数可以更好地优化lambdaexpression式。
另外,C ++编译器比普通函数更好地优化lambdaexpression式。 (页213)
这是为什么?
我认为当谈到内联时,应该没有任何区别了。 我能想到的唯一原因是编译器可能有一个更好的lambdaexpression式的本地环境,这样可以做更多的假设和执行更多的优化。
原因是lambdas是函数对象,所以将它们传递给一个函数模板将实例化一个专门用于该对象的新函数。 编译器可以轻松地内联lambda调用。
另一方面,对于函数,旧的注意事项适用于:函数指针传递给函数模板,编译器传统上通过函数指针内联调用有许多问题。 他们理论上可以内联,但只有当内联function也是内联的。
作为一个例子,考虑下面的函数模板:
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; });
结果在这个实例化(由编译器创build):
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
将创build一个新的实例化map
因为每个lambda具有不同的types。)
但是,当用函数指针调用时,实例化如下所示:
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
parsing为一个特定的函数。
因为当你向一个algorithm传递一个“函数”时,实际上是传入一个指向函数的指针,所以它必须通过函数指针进行间接调用。 当你使用一个lambda时,你传递一个对象到一个专门为这个types实例化的模板实例,对lambda函数的调用是直接调用,而不是通过函数指针调用,所以更可能内联。