简体   繁体   English

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

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

Trying to keep an object alive (but not needing to reference the shared_ptr to do so) I found myself writing stuff like this: 试图保持一个对象存活(但不需要引用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";
        }
    });
}

But then got an error in visual studio that said I couldn't copy-capture explicitly because I was already copy-capturing implicitly... This forced me to write: 但后来在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";
        }
    });
}

I know this works, but it feels wrong. 我知道这有效,但感觉不对。 Since I only need the side-effect of the shared_ptr ownership and do not need to reference it directly I would like to express this in the capture list instead of the lambda body. 由于我只需要shared_ptr所有权的副作用而不需要直接引用它,我想在捕获列表而不是lambda体中表达它。

In my real code I have about 5 or 6 variables I wanted to capture across a couple nested lambdas in network code and implicit capture was way nicer and easier to edit. 在我的真实代码中,我想要在网络代码中的几个嵌套lambda中捕获大约5或6个变量,并且隐式捕获更好更容易编辑。

My question is: is this standard behaviour or Visual Studio 2015's own take on lambda capture limitations? 我的问题是:这是标准行为还是Visual Studio 2015自己对lambda捕获的限制? Do newer versions of the standard allow for this, or has anyone talked about it? 该标准的较新版本允许这样做,还是有人谈过它?

Yes this is standard behavior. 是的,这是标准行为。 From C++14 (N4140) [expr.prim.lambda]/8 来自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 ”. 如果lambda-capture包含一个=capture-default ,则该lambda-capture的每个简单 捕获应为“ &identifier ”形式。

So if you have [=] then any other capture you do must be done by reference like 所以如果你有[=]那么你做的任何其他捕获都必须通过引用来完成

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

The rules do change in C++17 but it is to allow 规则确实在C ++ 17中有所改变,但它是允许的

[=, *this]{};

Which will capture a copy of the object into the lambda. 这将捕获对象的副本到lambda。

You can do what you want with an init-capture : 您可以使用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";
        }
    });
}

With the bonus that you don't have to declare self separately. 有奖金,您不必单独申报self

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

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