2016-06-10 67 views
5

试图保持一个活着的对象(但不是需要引用的shared_ptr这样做),我发现自己写的东西是这样的:C++:你可以做一个lambda隐式副本捕获加显式副本捕获吗?

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中说我不能复制错误-capture明确,因为我已经隐含复制捕捉...这迫使我写:

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个变量,我想通过嵌套在网络代码中的嵌套lambdas进行捕获,并且隐式捕获的方式更好,更易于编辑。

我的问题是:这是标准的行为还是Visual Studio 2015自带的lambda捕获限制?标准的更新版本是否允许这样做,还是有人提到过它?

+2

'[this,self]'? –

+2

或'self-> atomicCounter ++'。 – Jarod42

+1

[this,self]会很好,除了我有3个我想要捕捉的参数外,所以它看起来像:[this,self,p1,p2,p3],我实际上是这样做的,但后来决定比[=] {self; ...} @ KerrekSB – M2tM

回答

7

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

如果λ-捕获包括捕获默认=,即的每个简单捕获 λ捕获的形式应为“&标识符”。

所以如果你有[=],那么你做任何其他捕获必须由参考做过类似

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

的规则不改变C++ 17,但它是让

[=, *this]{}; 

这将捕获对象的一个​​副本到lambda中。

+1

我会很快接受你的答案,我想在isocpp板上发布这个问题一分钟,以便在我做这件事之前多看一些。谢谢。 – M2tM

+2

@ M2tM没问题。快乐编码:) – NathanOliver

1

你可以做你想做与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奖金。

+0

我相信这只在C++ 17中可用,但绝对是! – M2tM

+1

实际上它是[C++ 14](http://en.cppreference.com/w/cpp/language/lambda#Lambda_capture)。 –

相关问题