什么是广义Lambda捕获,为什么创建了它? [英] What is a generalized lambda capture and why was it created?

查看:71
本文介绍了什么是广义Lambda捕获,为什么创建了它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了很多问题,其中广义化的lambda捕获用于各种事物,但是没有什么能确切解释它们是什么或为什么将它们添加到标准中.

I see a lot of questions in which generalized lambda captures are used for various things, but nothing that explains exactly what they are or why they were added to the standard.

我已经阅读了文档,该文档描述了对通用化所必需的标准的更新lambda捕获确实存在,但是它并没有真正说明创建它们的原因,也没有真正给出它们如何工作的很好总结.基本上只是一堆枯燥的罢工这里,并在这里添加此语言"的东西.

I've read what appears to be the document describing the updated to the standard necessary for generalized lambda captures to exist, but it doesn't really say why they were created, nor does it really give a good summary of exactly how they work. It's mostly just a bunch of dry 'strike this out here and add this language here' stuff.

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

So, what are they? Why would I want to use one? What rules do they follow? For example, it seems to allow capture expressions. When are these expressions evaluated? If they result in side effects, when do those take effect? If several expressions are evaluated, is there a guaranteed evaluation order?

推荐答案

与往常一样,Scott Meyers在

As usual, Scott Meyers offers a great explanation of what they are, why you would want to use them, and roughly what rules they follow, in Effective Modern C++ Item 32: Use init capture to move objects into closures. Here is a short summary:

由于C ++ 11仅具有按值和按引用捕获,因此缺少按移动捕获. C ++ 14并未添加它,而是引入了通用lambda捕获,也称为初始捕获.它允许您指定

Since C++11 only has by-value and by-reference capture, by-move capture was missing. Instead of adding it, C++14 introduced the generalized lambda capture, also known as init capture. It allows you to specify

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

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

With this, an init capture is a new and more general capture mechanism, which covers the three above by-* captures and more (but no default capture mode).

回到逐行捕获的主要动机,它可以通过以下的init捕获来实现:

Coming back to the main motivation of by-move capture, it can be implemented by an init capture as follows:

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

// configure *pw

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

您可以使用

  • 手写课:

  • a hand-written class:

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);

  • 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) );
    

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

    Note that the parameter for the lambda is an lvalue reference (because the moved pw within the bind object is an lvalue) and has a const qualifier (to simulate the lambda's constness; so if the original lambda were declared mutable, the const qualifier would not be used).

    有关初始化捕获的一些详细信息,请参见 Anthony Calandra的备忘单现代的C ++语言和库功能,例如,初始化表达式是在创建lambda时(而不是在调用时)求值的.

    Some details about init captures is also given in Anthony Calandra's cheatsheet of modern C++ language and library features, for instance that the initializing expression is evaluated when the lambda is created (not when it is invoked).

    这篇关于什么是广义Lambda捕获,为什么创建了它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆