什么是广义 lambda 捕获,为什么创建它?

Omn*_*ous 4 c++ lambda c++14

我看到很多问题,其中广义 lambda 捕获用于各种事物,但没有任何内容可以确切解释它们是什么或为什么将它们添加到标准中。

我已经阅读了似乎是描述更新到通用 lambda 捕获存在所必需的标准文档,但它并没有真正说明创建它们的原因,也没有真正对它们的工作方式进行很好的总结。它主要只是一堆枯燥的“在此处删除并在此处添加此语言”的内容。

那么,它们是什么?为什么我要使用一个?他们遵循什么规则?例如,它似乎允许捕获表达式。什么时候评估这些表达式?如果它们会导致副作用,那么它们什么时候生效?如果计算多个表达式,是否有保证的计算顺序?

Dav*_*Far 7

像往常一样,Scott Meyers 在Effective Modern C++ Item 32: Use init capture to move objects into closures中对它们是什么、为什么要使用它们以及它们遵循的规则进行了很好的解释。这是一个简短的总结:

由于 C++11 只有按值和按引用捕获,因此缺少按移动捕获。C++14 没有添加它,而是引入了广义 lambda 捕获,也称为init capture。它允许您指定

  1. 从 lambda 生成的闭包类中的数据成员的名称,以及
  2. 初始化该数据成员的表达式。

有了这个,init 捕获是一种新的、更通用的捕获机制,它涵盖了上面三个 by-* 捕获和更多(但没有默认捕获模式)。

回到 by-move 捕获的主要动机,它可以通过 init 捕获来实现,如下所示:

auto pw = std::make_unique<Widget>(); 

// configure *pw

auto func = [pWidget = std::move(pw)] { 
    return pWidget->isValidated() && pWidget->isArchived(); 
};
Run Code Online (Sandbox Code Playgroud)

您可以在 C++11 中模拟一个 init 捕获

  • 手写类:

    class IsValAndArch {
    public:
        using DataType = std::unique_ptr<Widget>;
    
        explicit IsValAndArch(DataType&& ptr) : pw(std::move(ptr)) {}  
        bool operator()() const { return pw->isValid() && pw->isArchived(); }    
    
    private:
        DataType pw;
    };
    
    auto pw = std::make_unique<Widget>();
    
    // configure *pw;
    
    auto func = IsValAndArch(pw);
    
    Run Code Online (Sandbox Code Playgroud)
  • 或与std::bind

    auto pw = std::make_unique<Widget>();
    
    // configure *pw;
    
    auto func = std::bind( [](const std::unique_ptr<Widget>& pWidget)
        { return pWidget->isValidated() && pWidget->isArchived(); },
        std::move(pw) );
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,lambda 的参数是一个左值引用(因为pw在绑定对象中移动的是一个左值)并且有一个 const 限定符(以模拟 lambda 的常量性;因此如果原始 lambda 被声明为可变的,则 const 限定符将不会是用过的)。

Anthony Calandra 的现代 C++ 语言和库功能备忘单中还提供了有关 init 捕获的一些详细信息,例如,在创建 lambda 时(而不是在调用时)评估初始化表达式。