我很困惑为什么捕获lambda不可移动赋值,但它的手动定义(作为带运算符((的结构(是。
考虑以下简化代码:
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;
}
LambdaCPPInsights类是由cpp insights提供的已翻译(然后重命名(的lambda结构,因此应该与[env = env]() {}
定义的lambda相同。然而,在gcc11.2和c++20下的前一个代码的输出是:
True lambda is move-assignable: false
Manual lambda is move-assignable: true
godbolt的示例如下:https://godbolt.org/z/Yx3n9eGj5
我错过了什么?
带有捕获的lambda有一个已删除的复制赋值运算符,这也意味着它没有隐式的移动赋值运算符。参见[Epr.primλ闭包]/13。
您的LambdaCPPInsights
没有正确复制闭包类型。它应该显式默认复制和移动构造函数,并显式删除复制赋值运算符。