C++ 内联 lambda 参数

fak*_*ake 4 c++ lambda inline

考虑以下代码

#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) 只是一个可调用对象的包装器,实际类型已被擦除。


Yks*_*nen 5

如果您可以允许采用函数指针而不是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函数有一些限制,但另一方面,如果可能的话,编译器将在编译时执行它们。