C++ 内联 lambda 参数

C++ Inline lambda argument

考虑以下代码

#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;
}

编译

g++ -DLAMBDA -O2 -std=c++17 -S test.cpp -o test_long.S 

产生涉及跳转的代码,而

g++ -O2 -std=c++17 -S test.cpp -o test_short.S 

不会。哪一种有意义,但是否可以告诉编译器内联 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

[...] is it possible to tell the compiler to inline the lambda argument since it's known at compile time?

极不可能(换句话说 - ),这主要是因为您使用 std::function,由于其实现的性质,它使用 输入 erasure 并通过 动态分配 实现。当您调用它时,会进行虚拟调用,因此会发生跳转。为了内联代码,您可以切换到:

template <typename Callback>
inline void readandrun(Callback callback) {
    int i;
    i = 1;
    callback(i);
}

这样,lambda 的确切类型就会被推导出来,并且代码非常适合内联性。


记住 - lambda 的类型永远不会 std::function。它(std::function)只是一个可调用对象的包装器,实际类型已被擦除。

如果你允许使用函数指针而不是 std::function 作为你的参数,你可以使你的函数 constexpr:

constexpr void readandrun(void(*callback)(int)) {
    int i = 1; // can't use uninitialized variables in constexpr function
    callback(i);
}

See the assembly online

请注意,只有 non-capturing lambda 可以转换为函数指针。有关捕获 lambda 的信息,请参阅 。此外,constexpr 函数有一些限制,但另一方面编译器会尽可能在编译时执行它们。