为什么我们需要为 lambda 中的引用捕获引用?
why do we need to capture reference for a reference in lambda?
考虑一下:
class TestLambda {
public:
std::vector<char> data;
};
void test_lambda(TestLambda& obj) {
[=]() mutable {
obj.data.push_back(0x01);
}();
}
int main() {
TestLambda tst;
tst.data.push_back(0x99);
test_lambda(tst);
// tst.data is unchanged at this point
return 0;
}
调用 test_lambda
后,我期望看到 tst.data
中的变化,但事实并非如此。要查看更改,我必须创建 lambda 再次传递 obj
的引用,即。 [&obj]()
.
我们为什么需要这个?我的意思是,又是一个参考?
obj
已经是参考。然后,lambda
通过复制捕获 obj
。那么,lambda
中的 obj
本身不是引用?为什么?
有人能给我解释一下吗?谢谢。
根据草案标准§5.1.2/p15 Lambda 表达式[expr.prim.lambda](强调我的):
An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture
that is not of the form & identifier or & identifier initializer.
For each entity captured by copy, an unnamed non-static data member is
declared in the closure type. The declaration order of these members
is unspecified. The type of such a data member is the type of the
corresponding captured entity if the entity is not a reference to an
object, or the referenced type otherwise. [ Note: If the captured
entity is a reference to a function, the corresponding data member is
also a reference to a function. — end note ] A member of an anonymous
union shall not be captured by copy.
因此,在:
void test_lambda(TestLambda& obj) {
[=]() mutable {
obj.data.push_back(0x01);
}();
}
obj
被复制捕获,因此您正确地得到了描述的结果。换句话说,这是标准规定的 [=]
捕获默认值的行为。
当在赋值的右侧使用时,引用就像 "normal" 变量一样工作。每当您定义按值捕获的 lambda 时,lambda 都会拥有外部变量的副本,就像 lambda 以这些行开头一样:
auto my_inner_variable = my_outer_reference;
auto my_inner_other_variable = my_outer_other_variable;
如果你想引用 "remain" 一个引用,你必须通过引用捕获它,从而指示编译器发出这样的代码:
auto& my_inner_variable = my_outer_reference;
auto& my_inner_other_variable = my_outer_other_variable; // if we instructed to capture everything by reference
您的函数 test_lambda
包含一个嵌套的 lambda 函数。在 test_lambda
中,引用 obj
指的是 main 中的 tst
。然后调用按值捕获的匿名 lambda 函数。在 lambda 函数 obj
内部是 test_lambda 内部的 obj
的副本。为什么不简单地写:
void test_lambda(TestLambda& obj) {
obj.data.push_back(0x01);
}
你现在正在做的事情或许就是
void test_lambda(TestLambda& obj) {
[=]() mutable {
objCopy.data.push_back(0x01);
}();
}
其中 objCopy
是由捕获 lambda 的值创建的。
考虑一下:
class TestLambda {
public:
std::vector<char> data;
};
void test_lambda(TestLambda& obj) {
[=]() mutable {
obj.data.push_back(0x01);
}();
}
int main() {
TestLambda tst;
tst.data.push_back(0x99);
test_lambda(tst);
// tst.data is unchanged at this point
return 0;
}
调用 test_lambda
后,我期望看到 tst.data
中的变化,但事实并非如此。要查看更改,我必须创建 lambda 再次传递 obj
的引用,即。 [&obj]()
.
我们为什么需要这个?我的意思是,又是一个参考?
obj
已经是参考。然后,lambda
通过复制捕获 obj
。那么,lambda
中的 obj
本身不是引用?为什么?
有人能给我解释一下吗?谢谢。
根据草案标准§5.1.2/p15 Lambda 表达式[expr.prim.lambda](强调我的):
An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture that is not of the form & identifier or & identifier initializer. For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is the type of the corresponding captured entity if the entity is not a reference to an object, or the referenced type otherwise. [ Note: If the captured entity is a reference to a function, the corresponding data member is also a reference to a function. — end note ] A member of an anonymous union shall not be captured by copy.
因此,在:
void test_lambda(TestLambda& obj) {
[=]() mutable {
obj.data.push_back(0x01);
}();
}
obj
被复制捕获,因此您正确地得到了描述的结果。换句话说,这是标准规定的 [=]
捕获默认值的行为。
当在赋值的右侧使用时,引用就像 "normal" 变量一样工作。每当您定义按值捕获的 lambda 时,lambda 都会拥有外部变量的副本,就像 lambda 以这些行开头一样:
auto my_inner_variable = my_outer_reference;
auto my_inner_other_variable = my_outer_other_variable;
如果你想引用 "remain" 一个引用,你必须通过引用捕获它,从而指示编译器发出这样的代码:
auto& my_inner_variable = my_outer_reference;
auto& my_inner_other_variable = my_outer_other_variable; // if we instructed to capture everything by reference
您的函数 test_lambda
包含一个嵌套的 lambda 函数。在 test_lambda
中,引用 obj
指的是 main 中的 tst
。然后调用按值捕获的匿名 lambda 函数。在 lambda 函数 obj
内部是 test_lambda 内部的 obj
的副本。为什么不简单地写:
void test_lambda(TestLambda& obj) {
obj.data.push_back(0x01);
}
你现在正在做的事情或许就是
void test_lambda(TestLambda& obj) {
[=]() mutable {
objCopy.data.push_back(0x01);
}();
}
其中 objCopy
是由捕获 lambda 的值创建的。