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