Matthew
Matthew

Reputation: 867

cannot pass deleted lambda function with move?

I have the following lambda expression:

    auto pPerson = std::make_unique<Person>("Person");
    
    auto personLambda = [=, persPointer = std::move(pPerson)](int x, int y) mutable
    {
        //do stuff
    };

    acceptLambda(myVector, personLambda);//compiler error

acceptLambda():

template<typename Func>
void acceptLambda(std::vector<int> myVector, Func f) {
//do stuff
}

error:

function "lambda []std::string (int c, int y) mutable->std::string<unnamed>(const lambda []std::string (int x, int y) mutable->std::string &)" (declared implicitly) cannot be referenced -- it is a deleted function

As outlined above, I am running into a compiler error telling me I cannot pass this lambda into the acceptLamba() function. I have other lambdas above that work just fine; when I pass personLambda in (which contains an std::move in the capture clause) everything breaks.

When I remove the move operation on the unique_ptr, everything works as expected. However, I want to move this unique_ptr into the lambda for use in a concurrent environment and avoid a dangling pointer situation.

Why does the std::move operation cause this error? How does one remedy this issue?

Upvotes: 0

Views: 1092

Answers (1)

JaMiT
JaMiT

Reputation: 16873

Let's start with a the error message:

function "lambda []std::string (int c, int y) mutable->std::string<unnamed>(const lambda []std::string (int x, int y) mutable->std::string &)" (declared implicitly) cannot be referenced -- it is a deleted function

That's a mouthful. It's more understandable if you recognize that lambda []std::string (int c, int y) mutable->std::string is a name for the type of your lambda (apparently its return statement causes the auto to be deduced as std::string). Let's call that type L and see what the message looks like.

function "L(const L &)" (declared implicitly) cannot be referenced -- it is a deleted function

Your lambda's copy constructor is implicitly deleted. That should make sense since your lambda has captured a non-copyable value (the unique_ptr). And yet, you try to make a copy when you pass personLambda by value to acceptLambda. This does not work.

The full error message probably has more information that could help point you to seeing why your lambda cannot be copied. After the error line are probably some note lines explaining that unique_ptr cannot be copied. When using an IDE, such as Visual Studio, you might have to switch from the summary compiler output tab to the full compiler output tab to see this, though.

Option 1
You might be able to pass the lambda by reference. Might. Maybe you do need a copy in the larger scheme of things, but if you don't, then acceptLambda could take its second argument by reference (and probably should take the first argument by const reference).

void acceptLambda(const std::vector<int> & myVector, Func & f) 
//                                                        ^-- by reference

Option 2
You could get around being unable to copy your lambda the same way you got around being unable to copy your unique_ptr. You could move it. Just be aware that personLambda will not be usable after the call to acceptLambda. (If this is a problem, you likely should be using a shared_ptr instead of a unique_ptr.)

acceptLambda(myVector, std::move(personLambda));
//                     ^^^^^^^^^^            ^

Upvotes: 2

Related Questions