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

Lambda reinitialize vector - why does it work?

为什么下面的编译?

vector<int> vec;

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

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

如果我写:

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

这是无效的

这称为 init-capture。它声明了一个新变量,它隐藏了上面的 vec。它用于捕获 lambda 表达式中的仅移动类型:

An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression’s compound-statement, [..]

有关 cppreference 的更多信息。

这是一个没有进入 C++11 而是进入 C++14 的变化,我们可以从 N3610 中看到基本原理:

C++11 lambdas do not support capture-by-move. There has been at least two rejected NB comments on this for C++11, the first one was JP9 on CD1, the second was FI8 on FCD. FI8 refers to a Core reflector message by Roshan Naik, where Roshan explains that it would be very useful to be able to move-capture containers and other objects that are expensive to copy. Furthermore, move-only types like iostreams (especially stringstreams) and unique_ptrs can't be captured without wrapping them. This lack of cooperation between move semantics and lambdas was briefly discussed in the Evolution Working Group in Portland 2012 as one of potential extensions that would "complete C++11". Unfortunately, scheduling conflicts and lack of time has prevented producing a wording proposal for such an extension; this paper tries to explain the intended design

N3648引入了措辞:

For every init-capture a non-static data member named by the identifier of the init-capture is declared in the closure type. This member is not a bit-field and not mutable. The type of that member corresponds to the type of a hypothetical variable declaration of the form "auto init-capture ;", except that the variable name (i.e., the identifier of the init-capture) is replaced by a unique identifier. [ Note: This enables an init-capture like "x = std::move(x)"; the second "x" must bind to a declaration in the surrounding context. --end note ] No entity is captured by an init-capture. Within the lambda-expression's lambda-declarator and compound-statement, the identifier in the init-capture hides any declaration of the same name in scopes enclosing the lambda-expression. [ Example:

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.

--end example]

C++14 标准草案中的措辞发生了变化 N3936,尽管看起来像是格式化和清理。