Lambda 与普通函数的编译器优化
Nicolai Josuttis 在他的书《C 标准库(第二版)》中声称编译器可以比普通函数更好地优化 lambda。考虑到 lambda 表达式和普通函数都可以内联,这似乎有悖常理。但是,两者之间存在细微差别,可以在 lambda 的情况下进行更好的优化。
区别:函数对象与函数指针
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); }
编译器可以识别 lambda 的 operator() 以及对其进行简单的内联调用。
但是当用函数指针调用时:
map(begin(a), end(a), &multiply_by_two);
实例化变成:
template <> void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) { for (; begin != end; ++begin) *begin = f(*begin); }
这里,每次调用map时f都会引用不同的函数,防止编译器不会进行内联调用,除非 map 本身是内联的。
结论
作为函数对象的 lambda 的独特类型使编译器能够创建特定的函数实例化并无缝内联其调用。这种增强的优化功能将 lambda 与普通函数区分开来,使它们成为提高代码性能和效率的首选。
以上是编译器可以比普通函数更好地优化 Lambda 吗?的详细内容。更多信息请关注PHP中文网其他相关文章!