[英]Why won't this lambda capture this variable with a deleted constructor by reference?
我的编译器 Visual Studio 19 显示“正在尝试引用已删除的函数”:
class AClass
{public:
AClass(const AClass& other) = delete;
AClass() {}
AClass(AClass&& other) { }
AClass& operator=(const AClass& other) = delete;
AClass& operator=(AClass&& other) { return *this; }
int member;
};
void main()
{
AClass a;
AClass& aRef = a;
[=]() { return aRef.member; }; // "Attempting to reference a deleted function"
}
我假设它正在尝试调用已删除的复制构造函数,但我不明白为什么,因为我试图通过 [=] 值通过引用捕获,这意味着我不复制对象 AClass,我不看看如何涉及任何副本。 我的理解是 lambda 看起来像这样:
struct lambda {
AClass& refToAClass; // <--- this is the captured object
lambda(AClass& captureVariable) : refToAClass(captureVariable) {}
int operator()() const
{
return refToAClass.member;
}
};
void main()
{
// AND I CAN CONSTRUCT THE LAMBDA, NO COPYING OF AClass INVOLVED
AClass a;
AClass& aRef = a;
lambda lam(aRef); // WORKS FINE
}
本案如何涉及副本? 我如何捕获该参考?
从标准:
对于 copy 捕获的每个实体,在闭包类型中声明了一个未命名的非静态数据成员。 这些成员的声明顺序未指定。 如果实体是对对象的引用,则此类数据成员的类型是被引用类型,如果实体是对函数的引用,则是对被引用函数类型的左值引用,否则是对应的捕获实体的类型。 匿名工会的成员不得被复制。
cpprefence措辞更好:
每个数据成员的类型是对应的捕获实体的类型,除非实体具有引用类型(在这种情况下,对函数的引用被捕获为对被引用函数的左值引用,而对对象的引用被捕获为引用的对象)。
也许这有助于澄清我认为你对什么感到困惑:
template <typename T> void f(T arg) { }
int x = 10;
int& r = x;
auto y = r; // y is int (copied value from reference)
f(r); // T in f<T>() is deduced to int, arg in f() is int
在这两种情况下,如果您希望结果作为参考,则必须这样说:
template <typename T> void f(T& arg) { }
int x = 10;
int& r = x;
auto& y = r; // y is reference-to-int
f(r); // T in f<T>() is int, arg in f is ref-to-int
同样,在您的代码中:
AClass a;
AClass& aRef = a;
[=]() { return aRef.member; }; // "Attempting to reference a deleted function"
捕获的 aRef 是尝试从对不同对象的引用复制局部变量。 使用 [=] 表示按值复制,它不会将其读作“哦,源是引用,所以我将按值复制引用并将引用存储在引用中。” 它实际上说,“如果源类型有引用限定符,忽略 并考虑剩下的。你想按值复制吗?好的,我将一个 AClass 复制到一个新变量中。哦等等......不能。抱歉.”
你想要的是:
[&]() { return aRef.member; };
或者更具体地说:
[&aRef]() { return aRef.member; };
这告诉捕获的类型它应该是一个引用。 在这种情况下,源类型不如目标类型重要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.