为什么C ++编译器无法内联传递给函数模板的Lambda?

我的问题是Why can lambdas be better optimized by the compiler than plain functions?的反义词

  

原因是lambda是函数对象,因此将其传递到函数模板将实例化专门针对该对象的新函数。 编译器因此可以轻松地内联lambda调用。

因此,问题是什么情况下会导致编译器内联传递给内联函数模板的lambda?考虑以下设置:

template <typename F>
static inline void
hof(const F fun) {
    ...
    fun(a,b,c);     // a,c are int.
    ...
}
void
caller() {
    ...
    hof([&](int a,int b,int c) { ... });
    ...
}

进一步假设最近打开了所有相关优化标记的gcc或clang。

问题(以挑战的形式)是用代码填充...部分,以便编译器失败不能内联对{{1}的调用}或对hof的调用。您可以使用循环多次调用fun(但只能调用一次fun)。

我的主张是(不包括“滑稽生意”,例如例外,hof,反思等)无法做到。请尝试证明我错了。我将接受任何可以使用godbolt.org验证的lambda未内联的答案。

wjqact 回答:为什么C ++编译器无法内联传递给函数模板的Lambda?

只需要在lambda中填充足够的内容并至少使用两次即可(否则,没有充分的理由不进行内联)。

此处带有-O3的GCC 9.2和Clang 9:

#include<iostream>

int a,b,c;

template <typename F>
static inline void
hof(const F fun) {
    fun(a,c);
    fun(a,c);
}
void caller() {
    hof([&](int a,int b,int c) {
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
        std::cout << "Hello!";
    });
}

caller的程序集如下所示:

海湾合作委员会:

caller():
        sub     rsp,8
        call    caller()::{lambda(int,int,int)#1}::operator()(int,int) const [clone .isra.0]
        call    caller()::{lambda(int,int) const [clone .isra.0]
        add     rsp,8
        ret

C语:

caller():                             # @caller()
        push    rax
        call    caller()::$_0::operator()(int,int) const
        pop     rax
        jmp     caller()::$_0::operator()(int,int) const # TAILCALL

请参阅“ here”。

在我说服GCC两次内联不值得的情况下,这些正是lambda中的重复次数。

Clang已经停止内联,重复次数更少。

本文链接:https://www.f2er.com/3169550.html

大家都在问