考虑以下代码
#include <iostream>
#include <functional>
using namespace std;
inline void readandrun(function<void(int)> callback) {
int i;
i = 1;
callback(i);
}
int main(int argc, char *argv[])
{
#ifdef LAMBDA
readandrun([](int i){ printf("the read number is: %d\n",i);});
#else
int i;
i = 1;
printf("the read number is: %d\n",i);
#endif
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译
g++ -DLAMBDA -O2 -std=c++17 -S test.cpp -o test_long.S
Run Code Online (Sandbox Code Playgroud)
产生涉及跳转的代码,而
g++ -O2 -std=c++17 -S test.cpp -o test_short.S
Run Code Online (Sandbox Code Playgroud)
才不是。哪一种是有道理的,但是否可以告诉编译器内联 lambda 参数,因为它在编译时是已知的?我愿意切换编译器,但为了完整性:
$ g++ --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Run Code Online (Sandbox Code Playgroud)
Fur*_*ish 10
[...] 是否可以告诉编译器内联 lambda 参数,因为它在编译时是已知的?
极不可能(换句话说 -否),这主要是因为您使用std::functionwhich 由于其实现的性质,使用类型擦除并通过动态分配实现这一点。当您调用它时,会进行虚拟调用,因此会发生跳转。为了内联代码,您可以切换到:
template <typename Callback>
inline void readandrun(Callback callback) {
int i;
i = 1;
callback(i);
}
Run Code Online (Sandbox Code Playgroud)
这样,可以推导出 lambda 的确切类型,并且代码非常适合内联。
记住 - lambda 的类型是 never std::function。它 (the std::function) 只是一个可调用对象的包装器,实际类型已被擦除。
如果您可以允许采用函数指针而不是std::function作为参数,则可以使您的函数constexpr:
constexpr void readandrun(void(*callback)(int)) {
int i = 1; // can't use uninitialized variables in constexpr function
callback(i);
}
Run Code Online (Sandbox Code Playgroud)
请注意,只有非捕获 lambda 可以转换为函数指针。要捕获 lambda,请参阅Fureeish 的回答。此外,constexpr函数有一些限制,但另一方面,如果可能的话,编译器将在编译时执行它们。