C++:你能做一个 lambda 隐式复制捕获加上显式复制捕获吗?

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

试图让一个对象保持活动状态(但不需要引用 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";
        }
    });
}

但随后在 visual studio 中出现错误,说我无法显式复制捕获,因为我已经在隐式复制捕获...这迫使我写:

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 主体中表达它。

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

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

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

If a lambda-capture includes a capture-default that is =, each simple-capture of that lambda-capture shall be of the form “& identifier”.

因此,如果您有 [=],那么您所做的任何其他捕获都必须通过参考来完成,例如

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

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

[=, *this]{};

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

你可以用init-capture做你想做的事:

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