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

时间:2017-01-07 08:30:22

标签: c++ lambda c++14

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

我已经阅读了似乎是document describing the updated to the standard necessary for generalized lambda captures to exist的内容,但它并没有真正说出它们为什么被创建,也没有真正完整地概述它们是如何工作的。它主要只是一堆干'在这里罢工,并在这里添加这种语言'。

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

1 个答案:

答案 0 :(得分:4)

像往常一样,Scott Meyers在Effective Modern C++项目32:使用init捕获将对象移动到闭包中提供了一个很好的解释,它们是什么,为什么要使用它们,以及它们遵循的规则。这是一个简短的总结:

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

  1. 从lambda生成的闭包类中的数据成员的名称,以及
  2. 初始化该数据成员的表达式。
  3. 有了这个,初始捕获是一种新的更通用的捕获机制,它涵盖了上述三种 - *捕获和更多(但没有默认捕获模式)。

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

    auto pw = std::make_unique<Widget>(); 
    
    // configure *pw
    
    auto func = [pWidget = std::move(pw)] { 
        return pWidget->isValidated() && pWidget->isArchived(); 
    };
    

    您可以使用

    在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);
      
    • 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的constness;所以如果原始lambda被声明为可变的,不会使用const限定符。

    有关init捕获的一些细节也在Anthony Calandra's cheatsheet of modern C++ language and library features中给出,例如,在创建lambda时(而不是在调用它时)评估初始化表达式。