繁体   English   中英

为什么这个 lambda 不会通过引用通过删除的构造函数来捕获这个变量?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM