为什么C++编译器无法内联传递给函数模板的lambda
Why would a C++ compiler fail to inline a lambda passed to a function template?
我的问题是:为什么编译器可以比普通函数更好地优化lambda?公认的答案是
原因是lambda是函数对象,因此将它们传递到函数模板将实例化专门针对该对象的新函数编译器因此可以简单地内联lambda调用
因此,问题是什么情况会导致编译器不内联传递给内联函数模板的lambda?考虑以下设置:
template <typename F>
static inline void
hof(const F fun) {
...
fun(a, b, c); // a, b, c are int.
...
}
void
caller() {
...
hof([&](int a, int b, int c) { ... });
...
}
进一步假设最近的gcc或clang打开了所有相关的优化标志
问题(以质询的形式(是用代码填充...
部分,以便编译器无法内联对hof
的调用或对fun
的调用。您可以使用循环多次调用fun
或其他任何操作(但只能调用一次hof
(。
我的主张是(不包括异常、longjmp
、反思等"有趣的事情"(这是不可能的。请试着证明我错了。我将接受任何可以使用godbolt.org验证lambda没有内联的答案。
这只是向lambda中填充足够的内容并至少使用两次的问题(否则没有充分的理由不内联(。
此处为GCC 9.2和Clang 9与-O3
:
#include<iostream>
int a, b, c;
template <typename F>
static inline void
hof(const F fun) {
fun(a, b, c);
fun(a, b, c);
}
void caller() {
hof([&](int a, int b, int c) {
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
std::cout << "Hello!";
});
}
caller
的程序集如下所示:
GCC:
caller():
sub rsp, 8
call caller()::{lambda(int, int, int)#1}::operator()(int, int, int) const [clone .isra.0]
call caller()::{lambda(int, int, int)#1}::operator()(int, int, int) const [clone .isra.0]
add rsp, 8
ret
Clang:
caller(): # @caller()
push rax
call caller()::$_0::operator()(int, int, int) const
pop rax
jmp caller()::$_0::operator()(int, int, int) const # TAILCALL
请参阅此处的godbolt。
这些在lambda中的重复次数正好是我说服GCC两次内联不值得的次数
Clang已经停止了内联,重复次数更少。
相关文章:
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 为什么C++编译器无法内联传递给函数模板的lambda
- 无法在函数模板中使用 lambda 函数
- 关于函数模板中定义的 lambda 闭包类型可以说些什么?
- 在函数模板中使用lambda,无法推断类型,makeSet()用例
- C++如何将可变参数函数模板的参数包 -> 包装到 lambda 中
- C++11性能:Lambda内联与函数模板专业化
- 如何将模板 lambda 传递给函数并将其用于不同的类型
- lambda 是否应该替换 C++ 中的函数模板
- 如何将std ::函数或lambda作为(可选)模板参数
- 函数模板可用于本地lambda,但不能用于其他函数
- C++ lambda 表达式作为函数模板中的参数
- 将 lambda 传递到函数模板中
- Lambda函数无法调用函数模板参数的静态函数
- 可变模板函数接受lambda
- 将函数模板"pass"为泛型可变参数 lambda 返回语句是好方法吗?
- 模板化函数接受lambda问题
- c++可变模板std::函数到lambda的转换不工作
- 函数模板和lambda表达式的区别
- 为什么当我们向std::函数发送lambda时,自动模板类型推导不起作用