Redefining lambdas not allowed in C++11, why?

C++C++11LambdaLanguage Lawyer

C++ Problem Overview


Example:

#include <functional>

int main() {
  auto test = []{};
  test = []{};
    
  return 0;
}

This emits the following error message in gcc 4.7.2:

test.cpp: In function ‘int main()’:
test.cpp:5:13: error: no match foroperator=’ in ‘test = <lambda closure object>main()::<lambda()>{}’
test.cpp:5:13: note: candidate is:
test.cpp:4:16: note: main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&) <deleted>
test.cpp:4:16: note:   no known conversion for argument 1 frommain()::<lambda()>’ to ‘const main()::<lambda()>&’

From the standard 5.1.2.3 (emphasis mine):

>An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing: > >— the size and/or alignment of the closure type, > >— whether the closure type is trivially copyable (Clause 9) > >— whether the closure type is a standard-layout class (Clause 9), or > >— whether the closure type is a POD class (Clause 9).

As far as I can tell, this is what I'm running up against. It's attempting to use a deleted assignment operator and failing. I am curious to know if there's an easy workaround, and more broadly what the motivating rationale for allowing copy constructibility to be omitted for lambdas generally.

C++ Solutions


Solution 1 - C++

You seem to think that those two lambdas have the same type, but that is not true. Each one creates its own type:

#include <functional>
#include <type_traits>
#include <iostream>

int main() {
  auto test = []{};
  auto test2 = []{};
  std::cout << std::is_same< decltype( test ), decltype( test2 ) >::value << std::endl;
  return 0;
}

will print 0. Of course the error message you are getting from the compiler could be a little bit clearer in this regards...

Solution 2 - C++

> The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non- union class type

So it is like you are doing the following:

struct {} a;
struct {} b;
a = b; // error, type mismatch

Use std::function if you want to assign different lambdas with the same signature to the same variable.

std::function<void()> f = []{};
f = []{}; //ok

Solution 3 - C++

Lambda can't be redefined because each lambda is of a different, anonymous, incompatible type. They can be copied only if you pass them to a templated function (like std::function ctor) that would be able to deduce that type.

Solution 4 - C++

The reason you are not able to do this is because the copy assignment operator for the lambda-expression is declared deleted, See section 5.1.2/20 of the standard. For a more clear (for unusual definitions of clear) see this code sample

template<class T> void f(T x1)
{
  T x2 = x1; // copy constructor exists, this operation will succeed.
  x2 = x1; // assignment operator, deleted and will cause an error
}
int main()
{
  f([]{});
  return 0;
}

Other answers have pointed out that each lambda has a unique type, but this is not the reason why you are getting that error. This example shows that even if the two lambdas have the same type, it still is not able to copy it. However you are able to copy it to a new variable. This is the reason your error message is complaining about missing operator= and not about their types being different. Although each lambda having it's own type does not help you out much either.

Solution 5 - C++

If we could assign one lambda to another lambda of a different type, how do we copy the function bodies/definitions from that lambda to the other one? If we would be so stubborn, then we could use some member std::function-like type to be the one who will be copied. But that would be against the ol' C++ rule of not paying blah blah...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOmnipotentEntityView Question on Stackoverflow
Solution 1 - C++Daniel FreyView Answer on Stackoverflow
Solution 2 - C++Andrew TomazosView Answer on Stackoverflow
Solution 3 - C++J.N.View Answer on Stackoverflow
Solution 4 - C++RastabanView Answer on Stackoverflow
Solution 5 - C++Mark GarciaView Answer on Stackoverflow