Home > Software engineering >  Capturing lambda and move assignable
Capturing lambda and move assignable

Time:03-02

I am confused by why a capturing lambda is not move assignable, but its manual definition (as struct with operator()) is.

Consider the following simplified code:

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

The class LambdaCPPInsights is the translated (and then renamed) lambda struct as given by cpp insights, should therefore be the same thing as the lambda defined by [env = env]() {}. However, the output of the previous code under gcc 11.2 and c 20 is:

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

The example on godbolt is found here: https://godbolt.org/z/Yx3n9eGj5

What am I missing?

CodePudding user response:

A lambda with a capture has a deleted copy assignment operator, which also implies that it has no implicit move assignment operator. See [expr.prim.lambda.closure]/13.

Your LambdaCPPInsights is not correctly reproducing the closure type. It should explicitly default the copy and move constructors, and explicitly delete the copy assignment operator.

  • Related