Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error, cannot construct a copy of a lambda in constructor body [duplicate]

In the following, one way of initialising a member is accepted and the other is an error. I don't understand:

template <typename T>
struct LambdaHolder
{
    LambdaHolder(T lambdaIn) { lambda = lambdaIn; } // This will not work
    LambdaHolder(T lambdaIn) : lambda(lambdaIn) { } // This will work fine
    T lambda;
};


int main()
{
    auto lambda = []() { return 0; };
    LambdaHolder<decltype(lambda) > foo(lambda); // This will work only if the constructor argument is assigned in the initialiser list

// On the other hand
    int(*lambdaPtr)() = lambda; // A function pointer
    LambdaHolder<decltype(lambdaPtr)> foo(lambdaPtr); // Will work either in initialiser list or constructor body

}

I'm not understanding a couple of things. I know that certain members must be initialised in the member initialiser list, like references and const members. What I don't understand is why it will let me copy the lambda in the initialiser list but not in the constructor body. The error is "you cannot construct a copy of a lambda".

Also, I was able to create a pointer to the lambda, and initialising the pointer in either the initialiser list or the constructor body worked. Now, I know that lambdas and function pointers aren't exactly the same type, but the thing is that I thought that a captureless lambda is implemented as a free function, which is why you can set a normal function pointer to it, and also thought that when passing as an argument it would definitely decay to a pointer.

Basically I would like some clarification this, what's the difference for the distinction between initialising in the constructor body or initialiser list?

Edit: It seems, as Whoan has pointed out, that a lambda's default constructor's deleted before C++14, and non-existent after C++14 I think.

like image 518
Zebrafish Avatar asked Sep 26 '17 01:09

Zebrafish


People also ask

Is there a copy constructor available for the class 'Foo'?

class 'Foo': no copy constructor available or copy constructor is declared 'explicit' I've made the lambda mutable because I didn't want capture a const Foo, but what I think is happening is that the lambda can't be copied. Another compiler had a more useful error message:

Is it possible to create a lambda function in C++14?

This translates directly into a lambda (rafix07's answer explains how), because it captures Foo by value. The lambda itself is fine. For example, you can write But lambda's move constructor is ill-formed, and in C++11/14 it has to be well-formed for the line

What happens if I don't provide a constructor for my class?

If you don't provide a constructor for your class, C# creates one by default that instantiates the object and sets member variables to the default values as listed in the Default Values Table.

What are Lambda objects in C++?

A lambda object is really just an instance of an anonymous class (referred to as a ClosureType) that has a call operator ( operator ()) defined on it. This is a bit strange since C++ doesn't allow you to create anonymous classes explicitly, but it's analogous to anonymous classes in Java .


1 Answers

That is because lambdas are not Default Constructible:

Closure types are not DefaultConstructible. Closure types have "a deleted (until C++14) | no (since C++14)" default constructor.

In this constructor:

LambdaHolder(T lambdaIn) { lambda = lambdaIn; } // This will not work

...lambda needs to have been default constructed before being assigned.

like image 104
whoan Avatar answered Oct 09 '22 22:10

whoan