[英]Deducing Lambda Capture Types
我最近發現在 lambda 中按值捕獲const
對象意味着 labmda 主體內的變量(即 lambda 的數據成員)也是const
。
例如:
const int x = 0;
auto foo = [x]{
// x is const int
};
在C++17 草案的第 8.1.5.2 節中提到了這種行為:
對於副本捕獲的每個實體,在閉包類型中聲明了一個未命名的非靜態數據成員。 這些成員的聲明順序未指定。 如果實體是對對象的引用,則此類數據成員的類型是被引用類型,如果實體是對函數的引用,則是對被引用函數類型的左值引用,否則是對應的捕獲實體的類型。 匿名工會的成員不得被復制。
我希望推斷捕獲變量的類型與推斷自動相同。
對捕獲的類型有不同的類型推導規則是否有充分的理由?
在您的示例中,由於lambda不可mutable
,因此無法修改x
,這使得函數調用運算符const
。 但即使lambda是mutable
,引用的段落在lambda const int
的x
類型也是如此。
如果我沒記錯的話,這是C ++ 11中的一個深思熟慮的設計決定,使得在lambda中使用x
的行為類似於在封閉范圍內使用x
。 那是,
void foo(int&);
void foo(const int&);
const int x = 0;
foo(x); // calls foo(const int&)
auto foo = [x]() mutable {
foo(x); // also calls foo(const int&)
};
這有助於避免錯誤, 例如,某些代碼被重寫為具有使用lambda調用標准庫算法的顯式循環。
如果我對這個回憶錯了,希望有正確答案的人會介入並寫下自己的答案。
不是理由的答案; 已經有一個全面的答案在這里 。
對於那些想要知道如何捕獲const變量的非常量副本的人,可以使用帶有初始化器的捕獲:
const int x = 0;
auto foo = [x = x]() mutable {
// x is non-const
};
這需要C ++ 14。 兼容C ++ 11的解決方案是在lambda之外創建副本:
const int x = 0;
int copy = x;
auto foo = [copy]() mutable {
// copy is non-const
};
原因是lambda中的operator()
默認為const
。
int main()
{
const int x = 0;
auto foo = [x](){}; // main::$_0::operator()() const
foo();
}
所以你必須使用mutable
lambda:
int main()
{
const int x = 0;
auto foo = [x=x](){}; // main::$_0::operator()()
foo();
}
對捕獲的類型有不同的類型推導規則是否有充分的理由?
這是經過深思熟慮的決定(其理由/原因引自下面的 CWG 756),並且是重寫原始 lambda 提案的一部分,
經過
在 2009 年 3 月的 Summit 會議上,核心工作組 (CWG) 提出並審查了大量與 C++0x Lambda 相關的問題。 在為大多數這些問題確定了明確的方向后,CWG 得出結論,最好重寫有關 Lambda 的部分以實現該方向。 本文介紹了這種重寫。
特別是它的 CWG 756 [強調我的] 決議:
[...] 考慮以下示例:
void f() { int const N = 10; [=]() mutable { N = 30; } // Okay: this->N has type int, not int const. N = 20; // Error. }
也就是說,作為閉包對象成員的 N 不是 const,即使捕獲的變量是 const。 這看起來很奇怪,因為捕獲基本上是一種以避免生命周期問題的方式捕獲本地環境的方法。 更嚴重的是,類型的變化意味着應用於 lambda 表達式中捕獲的變量的 decltype、重載解析和模板參數推導的結果可能與包含 lambda 表達式的范圍內的結果不同,這可能是錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.