捕获 lambda 并移动可赋值

Capturing lambda and move assignable

我很困惑为什么捕获的 lambda 不是可移动赋值的,但它的手动定义(作为带有 operator() 的结构)是。

考虑以下简化代码:

struct Environment {
  Environment(std::unique_ptr<int>&& p): ptr(std::move(p)) {}
  
  std::unique_ptr<int> ptr;
};

class LambdaCPPInsights
{
  public: 
  inline /*constexpr */ void operator()() const
  {
  }

  private: 
  std::shared_ptr<Environment> env;
  public: 
  LambdaCPPInsights(const std::shared_ptr<Environment> & _env)
    : env{_env}
  {}

};

constexpr const char* btos(bool b)
{
   return b ? "true" : "false";
}

int main()
{
  
  auto env =  std::make_shared<Environment>(std::make_unique<int>(4));
  
   std::cout << "True   lambda is move-assignable: " << btos(std::is_move_assignable_v< decltype([env = env]() {}) >) << std::endl;
   std::cout << "Manual lambda is move-assignable: " << btos(std::is_move_assignable_v< LambdaCPPInsights >);  

  return 0;
}

class LambdaCPPInsights 是 cpp insights 给出的翻译(然后重命名)lambda 结构,因此应该与 [env = env]() {} 定义的 lambda 相同。 但是之前的代码在gcc 11.2和c++20下的输出是:

True   lambda is move-assignable: false
Manual lambda is move-assignable: true

godbolt 的例子可以在这里找到:https://godbolt.org/z/Yx3n9eGj5

我错过了什么?

带有捕获的 lambda 具有删除的复制赋值运算符,这也意味着它没有隐式移动赋值运算符。参见 [expr.prim.lambda.closure]/13

您的 LambdaCPPInsights 没有正确重现闭包类型。它应该显式默认复制和移动构造函数,并显式删除复制赋值运算符。