Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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:

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.

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.

My question is: is this standard behaviour or Visual Studio 2015's own take on lambda capture limitations? Do newer versions of the standard allow for this, or has anyone talked about it?

like image 284
M2tM Avatar asked Jun 10 '16 17:06

M2tM


1 Answers

Yes this is standard behavior. From 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”.

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

[=, *this]{};

Which will capture a copy of the object into the lambda.

like image 120
NathanOliver Avatar answered Nov 15 '22 03:11

NathanOliver