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.