c++ - "Empty base optimization"用于 lambda 捕获 - 被标准禁止?为什么?

标签 c++ lambda c++17

我最近遇到了一种情况,我最终得到了大量嵌套的 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 捕获占用额外空间的内容?如果是,为什么?

最佳答案

来自 expr.prim.lambda.capture :

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 通过复制捕获 tp,因此有两个未命名的非静态数据成员。每个 .then() 添加另一个成员变量,即使每个成员变量都是空的,因此节点的大小不断增加。

或者换句话说,空基数优化只适用于基数,lambdas 的捕获不会创建基数,它会创建非静态数据成员。

关于c++ - "Empty base optimization"用于 lambda 捕获 - 被标准禁止?为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45056703/

相关文章:

c++ - Thread.join() 给我一个错误?

java - 是否可以使用 Java Lambda 来实现类似 Groovy 的 SwingBuilder 之类的东西?

c++ - 如果结构化绑定(bind)不能是 constexpr 为什么它们可以在 constexpr 函数中使用?

c++ - 在指针场景中使用 std::shared_ptr

c++ - 实例化模板参数的参数包

c++ - 如何递归查找最大数组元素的索引

c++ - include <name.h> 和 libname.o 处的库名称之间的链接

c++ - 如何删除指向动态分配对象内的动态分配对象的指针?

python - Pandas 将 lambda 应用于整个数据框

c# - 使用 Linq 将 List<string> 转换为 List<KeyValuePair<string, string>>