我最近遇到了一种情况,我最终得到了大量嵌套的 lambda 表达式到 build asynchronous computation chains。 .
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);
}
我在 lambda 中捕获的所有对象都是空,但最终对象的大小大于一个:example on gcc.godbolt.org .
如果我更改 node</* ... */>::then
中的 lambda对于具有显式 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
我觉得这很烦人,因为我不得不:
编写大量与 lambda 大致相同的样板代码。
由于 EBO 之类的东西不适用于 lambda 捕获,因此需要支付额外的内存成本。
标准中是否有明确强制空 lambda 捕获占用额外空间的内容?如果是,为什么?
最佳答案
For each entity captured by copy, an unnamed non-static data member is declared in the closure type.
虽然这里的 lambda 没有捕获:
auto f = node{[]{ }}.then([]{ }).then([]{ });
因此没有未命名的非静态数据成员,因此是空的,这不是 then()
实际使用的。它使用这个:
return ::node{[p = std::move(*this), t = std::move(f_then)](){}};
that lambda 通过复制捕获 t
和 p
,因此有两个未命名的非静态数据成员。每个 .then()
添加另一个成员变量,即使每个成员变量都是空的,因此节点的大小不断增加。
或者换句话说,空基数优化只适用于基数,lambdas 的捕获不会创建基数,它会创建非静态数据成员。
关于c++ - "Empty base optimization"用于 lambda 捕获 - 被标准禁止?为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45056703/