为什么以下编译?
vector<int> vec;
auto lambda = [ vec (move(vec)) ]() { //??
};
如何使用vec (move(vec))
重新初始化已分配的vec变量?这不是调用移动构造函数吗?
如果我写:
vector<int> vec;
vec (move(vec));
这是无效的
答案 0 :(得分:5)
这称为 init-capture 。它声明了一个新变量,它隐藏了上面的vec
。它曾用于捕获lambda表达式中的仅移动类型:
init-capture 的行为就像声明并显式捕获“
auto init-capture ;
”形式的变量一样 其声明区域是lambda表达式的复合语句,[..]
有关cppreference的更多信息。
答案 1 :(得分:4)
这是一个没有进入C ++ 11而是C ++ 14的变化,我们可以从N3610看到基本原理:
C ++ 11 lambdas不支持逐个移动。对于C ++ 11,至少有两个被拒绝的NB评论,第一个是CD1上的JP9,第二个是FCD上的FI8。 FI8引用Roshan Naik的Core反射器消息,其中Roshan解释说,能够移动捕获容器和其他复制昂贵的对象非常有用。此外,如果不包装它们,则无法捕获像iostreams(尤其是stringstreams)和unique_ptrs这样的仅移动类型。移动语义和lambdas之间缺乏合作在2012年波特兰的演化工作组中进行了简要讨论,作为“完成C ++ 11”的潜在扩展之一。不幸的是,安排冲突和缺乏时间阻碍了为这种延期提出措辞建议;本文试图解释预期的设计
并且N3648引入了措辞:
对于每个init-capture,由一个名为的静态数据成员 init-capture的标识符在闭包类型中声明。这个 成员不是一个位域而不是可变的。该成员的类型 对应于的假设变量声明的类型 形成“auto init-capture;”,但变量名称除外(即 init-capture的标识符由唯一标识符替换。 [ 注意:这会启用init-capture,例如“x = std :: move(x)”;第二 “x”必须绑定到周围环境中的声明。 - 结束说明 ]初始捕获没有捕获任何实体。内 lambda-expression的lambda-declarator和compound-statement ,. init-capture中的标识符隐藏任何相同名称的声明 在包含lambda表达式的范围内。 [例如:
int x = 4; auto y = [&r = x, x = x+1]()->int { r += 2; return x+2; }(); // Updates ::x to 6, and initializes y to 7.
- 结束示例]
C ++ 14标准N3936草案中的措辞发生了变化,尽管它看起来像格式化和清理。