为什么一个只返回有状态 lambda 的函数会编译成任何程序集?

问题描述 投票:0回答:1

以下非模板化(或者是吗?)函数返回非泛型、有状态 lambda,

auto foo(double a) {
    return [a](double b) -> double {
        return a + b;
    };
}

用 GCC 或 Clang 编译成这个样子。为什么?

foo(double):
        ret

我希望它会生成根本没有输出


问题的由来

我什至不记得为什么我开始写上面的片段,但无论如何......

最初我认为它应该编译成稍微长一点的东西,因为我期望至少看到一个

add
指令。

但是后来我意识到上面的

foo
不能在cpp中单独编译,然后链接到使用它的另一个TU,因为我什至无法为它编写声明

所以我想说的是,在非头文件中编写该函数的唯一原因是它在该非头文件中使用,此时编译器可能可以在任何使用它的地方内联它。

但如果是这样的话……那么为什么要将

foo
复制到 anything,如果它是 TU 中唯一的东西呢?没有任何东西可以链接,那么为什么要为其生成 any 输出?


使用

struct
+
operator()
不会改变任何东西,因为这

struct Bar {
    double a;
    double operator()(double b) const {
        return a + b;
    }
};

Bar bar(double a) {
    return Bar{a};
}

生成相同的仅限

ret
的代码,事后看来这也是显而易见的,因为如果
bar
隐藏在 cpp 文件中,则甚至无法从其他 TU 链接到此
Bar
函数。

c++ assembly gcc lambda higher-order-functions
1个回答
0
投票

看起来像是 GCC 和 Clang 可能不会尝试寻找的错过的优化。 他们必须运行额外的优化过程,寻找像这样返回 lambda 的函数,并将它们视为

inline
,这样他们就可以避免在不需要的 TU 中发出独立的定义。

但如果他们这样做,他们将无法在链接时检测到违反单一定义规则的情况。
因此,这是不将其视为

inline
并且不发出 asm 的充分理由。

但我猜他们可能只发出一个

.global foo
foo:
定义 ODR 违规检测的符号,无需在
ret
上花费任何代码大小。 这将是生成 asm 的特殊情况,并且可能不值得在 GCC 或 Clang 内部添加额外的代码来跟踪它应该得到的特殊处理并执行它。

这种优化的价值非常小,因为正如您所说,这只是实际程序中的死代码,其中该函数位于 TU 中,没有任何调用它的东西。 寻找它会花费编译时间,并且是 GCC / Clang 开发人员必须维护的代码。

© www.soinside.com 2019 - 2024. All rights reserved.