繁体   English   中英

为什么我们需要捕获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不是引用? 为什么?

有人能解释一下吗? 谢谢。

当在分配的右侧使用时,引用就像“正常”变量一样。 每当你通过值定义lambda捕获时,lambda拥有外部变量的副本,就像lambda以这些行开头一样:

auto my_inner_variable = my_outer_reference;
auto my_inner_other_variable = my_outer_other_variable;

如果您希望引用“保留”引用,则必须通过引用捕获它,从而指示编译器发出如下代码:

auto& my_inner_variable = my_outer_reference;
auto& my_inner_other_variable = my_outer_other_variable; // if we instructed to capture everything by reference

根据标准草案§5.1.2/ p15 Lambda表达式[expr.prim.lambda]Emphasis Mine ):

如果隐式捕获实体,并且capture-default为=,或者如果使用不是形式&identifier或&identifier初始化程序的捕获显式捕获实体,则通过副本捕获实体。 对于由副本捕获的每个实体,在闭包类型中声明未命名的非静态数据成员。 这些成员的声明顺序未指定。 如果实体不是对对象的引用,则这种数据成员的类型是对应的捕获实体的类型,否则是引用的类型。 [注意:如果捕获的实体是对函数的引用,则相应的数据成员也是对函数的引用。 - 结束注释]匿名工会的成员不得通过副本获取。

因此,在:

void test_lambda(TestLambda& obj) {
    [=]() mutable {
        obj.data.push_back(0x01);
    }();
}

obj是通过复制捕获的,因此您可以正确地获得所描述的结果。 换句话说,这是标准规定[=]捕获默认值的行为。

您的函数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的值创建的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM