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