Это всего лишь вопрос заполнения достаточного количества материала в лямбду и его использования по крайней мере дважды (в противном случае нет веских оснований не указывать в строке).
Здесь для GCC 9.2 и Clang 9 с -O3
:
#include<iostream>
int a, b, c;
template <typename F>
static inline void
hof(const F fun) {
fun(a, b, c);
fun(a, b, 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
выглядит следующим образом:
GCC:
caller():
sub rsp, 8
call caller()::{lambda(int, int, int)#1}::operator()(int, int, int) const [clone .isra.0]
call caller()::{lambda(int, int, int)#1}::operator()(int, int, int) const [clone .isra.0]
add rsp, 8
ret
Clang:
caller(): # @caller()
push rax
call caller()::$_0::operator()(int, int, int) const
pop rax
jmp caller()::$_0::operator()(int, int, int) const # TAILCALL
См. godbolt здесь .
Это ровно столько же повторений в лямбде, сколько мне нужно, чтобы убедить GCC, что вставка дважды не стоит.
Clang прекратил вставку уже с меньшим количествомповторы.