C++:您能否执行 lambda 隐式复制捕获和显式复制捕获

C++: Can you do a lambda implicit copy capture plus explicit copy capture?

本文关键字:复制 lambda 执行 C++      更新时间:2023-10-16

试图让一个对象保持活动状态(但不需要引用shared_ptr来这样做)我发现自己写了这样的东西:

void ClassDerivedFromSharedFromThis::countdown(ThreadPool &pool, std::string name){
    auto self = shared_from_this();
    pool.then([=, self]{
        for(int i = 0;i < 10;++i){
            atomic_cout() << "Hey [" << name << "]! Our counter is: " << atomicCounter++ << "n";
        }
    });
}

但是后来在视觉工作室中出现一个错误,说我无法显式复制捕获,因为我已经在隐式复制捕获......这迫使我写:

void countdown(ThreadPool &pool, std::string name){
    auto self = shared_from_this();
    pool.then([=]{
        self; //Capture self.
        for(int i = 0;i < 10;++i){
            atomic_cout() << "Hey [" << name << "]! Our counter is: " << atomicCounter++ << "n";
        }
    });
}

我知道这行得通,但感觉不对。由于我只需要shared_ptr所有权的副作用,不需要直接引用它,因此我想在捕获列表中而不是 lambda 正文中表达这一点。

在我的真实代码中,我想在网络代码中的几个嵌套 lambda 中捕获大约 5 或 6 个变量,隐式捕获更好、更容易编辑。

我的问题是:这是标准行为还是Visual Studio 2015自己对lambda捕获限制的看法?较新版本的标准是否允许这样做,或者有人谈论过它?

是的,这是标准行为。 从 C++14 (N4140) [expr.prim.lambda]/8

如果 lambda 捕获包含=的捕获默认值,则该 lambda 捕获的每个简单捕获应采用"&标识符"的形式。

因此,如果您有[=]那么您必须通过引用完成的任何其他捕获,例如

[=, &some_var]{} // copy all implicitly but explicitly capture some_var by reference

规则确实在 C++17 中发生了变化,但它是允许的

[=, *this]{};

这会将对象的副本捕获到 lambda 中。

你可以用初始化捕获做你想做的事:

void ClassDerivedFromSharedFromThis::countdown(ThreadPool &pool, std::string name){
    pool.then([=, self=shared_from_this()]{
        for(int i = 0;i < 10;++i){
            atomic_cout() << "Hey [" << name << "]! Our counter is: " << atomicCounter++ << "n";
        }
    });
}

奖金是您不必单独申报self