Недавно я столкнулся с ситуацией, когда у меня оказалось большое количество вложенных лямбда-выражений для построения цепочек асинхронных вычислений< /а>.
template <typename F>
struct node : F
{
node(F&& f) : F{std::move(f)}
{
}
template <typename FThen>
auto then(FThen&& f_then)
{
return ::node{[p = std::move(*this), t = std::move(f_then)]()
{
}};
}
};
int main()
{
auto f = node{[]{ }}.then([]{ }).then([]{ });
return sizeof(f);
}
Все объекты, которые я фиксирую в своих лямбда-выражениях, пусты, однако размер конечного объекта больше единицы: пример на gcc.godbolt.org.
Если я изменю лямбду внутри node</* ... */>::then на функциональный объект с явным EBO, размер конечного объекта станет равным единице.
template <typename P, typename T>
struct node_lambda : P, T
{
node_lambda(P&& p, T&& t) : P{std::move(p)}, T{std::move(t)}
{
}
void operator()()
{
}
};
template <typename FThen>
auto node</* ... */>::then(FThen&& f_then)
{
return ::node{node_lambda{std::move(*this), std::move(f_then)}};
}
Live example on gcc.godbolt.org
Меня это очень раздражает, потому что я вынужден либо:
Напишите много шаблонного кода, который примерно эквивалентен лямбда-выражению.
Заплатите дополнительную стоимость памяти из-за того, что что-то вроде EBO не применяется к лямбда-захватам.
Есть ли в стандарте что-то, что явно заставляет пустые лямбда-выражения занимать дополнительное место? Если да, то почему?