Lambda重新初始化矢量 - 为什么它有效?

时间:2015-04-20 20:21:25

标签: c++ lambda c++14

为什么以下编译?

vector<int> vec;

auto lambda = [ vec (move(vec)) ]() {  //??      
};

如何使用vec (move(vec))重新初始化已分配的vec变量?这不是调用移动构造函数吗?

如果我写:

vector<int> vec;
vec (move(vec));

这是无效的

2 个答案:

答案 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草案中的措辞发生了变化,尽管它看起来像格式化和清理。