有没有办法检查编译器是否内联了 C++ lambda 函数?

Lon*_*ong 7 c++ c++11

我正在使用 C++ lambdas 进行编程。出于性能原因,我想确保对 lambda 的调用由编译器内联。例如,我有这段简化的代码:

template <typename T>
auto gen_fn1(T x1, T x2) {
    auto fn1 = [x1, x2]() {
        return x1 + x2;
    };
    return fn1;
}

template <typename T>
auto gen_fn2(T x1, T x2) {
    auto fn2 = [x1, x2]() {
        auto fn1 = gen_fn1(x1, x2);
        return fn1() * fn1();
    };
    return fn2;
}

int test_1() {
    auto fn2 = gen_fn2(1, 2);
    return fn2();
}
Run Code Online (Sandbox Code Playgroud)

我想确保 test_1() 中的 lambda 生成和调用不会引入额外的成本。我可以手动检查编译生成的汇编代码。通过 clang++8 的“-O2”优化,我可以看到预期的结果:在生成的代码中几乎只是“返回 9”。所以我的问题是:有没有办法自动检查我总能得到想要的结果?特别是,我想检查:

  1. 没有用于在“test_1()”中生成 lambda 的方法调用,包括“gen_fn2()”和“gen_fn1()”。
  2. 'test_1()' 或 'gen_fn2()' 中没有 lambda 调用成本,如 'fn1()' 和 'fn2()'。我希望它们可以内联。那么如何识别它们并检查它们是否已内联?

问题 2 对我来说更有趣。能够以可编程的方式检查它是最值得赞赏的,例如'assert(gen_fn2(1, 2) == ()[]{ return 9; }'。如果不可能,检查编译器的中间文件也有帮助, 或程序集文件。但是如何呢?

ein*_*ica 3

TL;DR:如果不查看编译输出就无法做到这一点。

首先,正如其他答案所指出的,C++ lambda 基本上是带有operator()方法的匿名类;所以,你的问题与“有没有办法检查对象方法的某个调用是否被内联?”没有什么不同。

方法调用是否内联是编译器的选择,并且不是语言规范强制要求的(尽管在某些情况下不可能内联)。因此,这一事实并未在语言本身中体现(也没有在语言的编译器扩展中体现)。

您可以做以下两件事之一:

  • 外部检查编译输出(最简单的方法是在不进行汇编的情况下进行编译,例如gcc -Sclang++ -S,加上任何优化标志和其他编译选项。但请记住,即使在编译期间没有发生内联,理论上它仍然可能发生在链接处-时间。
  • 在内部,尝试确定内联选择的副作用。例如,您可以有一个函数来获取您要检查的函数的地址;然后你在运行时读取该函数的指令,看看它是否有任何函数调用,在符号表中查找被调用的地址,并查看符号名称是否来自某个 lambda。这已经相当困难、容易出错、平台特定且脆弱——而且事实上您可能在同一个函数中使用了两个 lambda。所以我显然不建议这样做。