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 for ‘operator=’ 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 from ‘main()::<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.
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...
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
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.
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.
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...
Related
Link https://cplusplus.github.io/LWG/issue2067 provides the following discussion:
Class template packaged_task is a move-only type with the following form of the deleted copy operations:
packaged_task(packaged_task&) = delete;
packaged_task& operator=(packaged_task&) = delete;
Note that the argument types are non-const. This does not look like a typo to me, this form seems to exist from the very first proposing paper on N2276. Using either of form of the copy-constructor did not make much difference before the introduction of defaulted special member functions, but it makes now an observable difference. This was brought to my attention by a question on a German C++ newsgroup where the question was raised why the following code does not compile on a recent gcc:
#include <utility>
#include <future>
#include <iostream>
#include <thread>
int main() {
std::packaged_task<void()> someTask([]{ std::cout << std::this_thread::get_id() << std::endl; });
std::thread someThread(std::move(someTask)); // Error here
// Remainder omitted
}
It turned out that the error was produced by the instantiation of some return type of std::bind which used a defaulted copy-constructor, which leads to a const declaration conflict with [class.copy] p8.
Some aspects of this problem are possibly core-language related, but I consider it more than a service to programmers, if the library would declare the usual form of the copy operations (i.e. those with const first parameter type) as deleted for packaged_task to prevent such problems.
Could anybody explain the meaning of the marked statement? I don't undestand how the missing const qualifer affects the compilation process, and how this behavior is explained in standard.
What is the point of adding const to the parameter of the deleted copy constructor?
Here is a toy example:
struct problem {
problem()=default;
problem(problem&&)=default;
problem(problem&)=delete;
};
template<class T>
struct bob {
T t;
bob()=default;
bob(bob&&)=default;
bob(bob const&)=default;
};
int main() {
problem p;
problem p2 = std::move(p);
bob<problem> b;
bob<problem> b2 = std::move(b);
}
bob<problem> fails to compile because the bob(bob const&)=default errors out when it interacts with problem(problem&)=delete.
Arguably the standard "should" error-out cleanly when it determines that it cannot implement bob(bob const&), and treat the =default as =delete (like it would if we had problem(problem const&)=delete), but the standard wording isn't going to be flawless in this corner case of a corner case. And this corner of a corner case is going to be strange and quirky enough that I'm not certain a general rule that makes it translate =default to =delete would be right!
The fix if we problem(problem const&)=delete (well, to packaged_task) is going to be so much cleaner than anything we do to =default ctor rules.
Now standard delving:
First, it is obvious that the implicitly declared copy constructor of bob<problem> above is going to have signature bob(bob&) in [class.ctor]. I won't even quote the standard for that, because lazy.
We go and explicitly default bob(bob const&) copy ctor, which differs in signature from the one that would be implicitly declared.
There are rules about explicitly defaulting functions and their conflict with the signatures is in 11.4.2.
In Explicitly-defaulted functions[dcl.fct.def.default] 11.4.2/2
2 The typeT1of an explicitly defaulted function F is allowed to differ from the type T2 it would have had if it were implicitly declared, as follows:
—(2.1) T1 and T2 may have differing ref-qualifiers; and
—(2.2) if T2 has a parameter of type const C&, the corresponding parameter of T1 may be of type C&.
If T1 differs from T2 in any other way, then:
—(2.3) if F is an assignment operator, and the return type of T1 differs from the return type of T2 or T1’s parameter type is not a reference, the program is ill-formed;
—(2.4) otherwise, if F is explicitly defaulted on its first declaration, it is defined as deleted;
—(2.5) otherwise, the program is ill-formed.
The defaulted one is T1, which contains const& not &, so (2.2) doesn't apply.
My reading actually has it getting caught on (2.4); the type of bob(bob const&) differs from the implicitly declared bob(bob&) in an impermissible way; but first declaration is defaulted, so it should be deleted.
I'm looking at the n4713 draft version; maybe an older version didn't have that clause.
Just found the reason for an insidious crash to be a unchecked wild cast by the compiler, disregarding the types. Is this intended behaviour or a compiler bug?
Problem: When a type definition is involved, it is possible to make an implicit reinterpret cast, undermining the type system.
#include <iostream>
template<class A, class B>
inline bool
isSameObject (A const& a, B const& b)
{
return static_cast<const void*> (&a)
== static_cast<const void*> (&b);
}
class Wau
{
int i = -1;
};
class Miau
{
public:
uint u = 1;
};
int
main (int, char**)
{
Wau wau;
using ID = Miau &;
ID wuff = ID(wau); // <<---disaster
std::cout << "Miau=" << wuff.u
<< " ref to same object: " <<std::boolalpha<< isSameObject (wau, wuff)
<< std::endl;
return 0;
}
I was shocked to find out that gcc-4.9, gcc-6.3 and clang-3.8 accept this code without any error and produce the following output:
Miau=4294967295 ref to same object: true
Please note I use the type constructor syntax ID(wau). I would expect such behaviour on a C-style cast, i.e. (ID)wau. Only when using the new-style curly braces syntax ID{wau} we get the expected error...
~$ g++ -std=c++11 -o aua woot.cpp
woot.cpp: In function ‘int main(int, char**)’:
woot.cpp:31:21: error: no matching function for call to ‘Miau::Miau(<brace-enclosed initializer list>)’
ID wuff = ID{wau};
^
woot.cpp:10:7: note: candidate: constexpr Miau::Miau()
class Miau
^~~~
woot.cpp:10:7: note: candidate expects 0 arguments, 1 provided
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(const Miau&)
woot.cpp:10:7: note: no known conversion for argument 1 from ‘Wau’ to ‘const Miau&’
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(Miau&&)
woot.cpp:10:7: note: no known conversion for argument 1 from ‘Wau’ to ‘Miau&&’
Unfortunately, the curly-braces syntax is frequently a no-go in template heavy code, due to the std::initializer_list fiasco. So for me this is a serious concern, since the protection by the type system effectively breaks down here.
Can someone explain the reasoning behind this behaviour?
Is it some kind of backwards compatibility (again, sigh)?
To go full language-lawyer, T(expression) is a conversion of the result of expression to T1. This conversion has as effect to call the class' constructor2. This is why we tend to call a non-explicit constructor taking exactly one argument a conversion constructor.
using ID = Miau &;
ID wuff = ID(wau);
This is then equivalent to a cast expression to ID. Since ID is not a class type, a C-style cast occurs.
Can someone explain the reasoning behind this behaviour?
I really can't tell why is was ever part of C++. This is not needed. And it is harmful.
Is it some kind of backwards compatibility (again, sigh)?
Not necessarily, with C++11 to C++20 we've seen breaking changes. This could be removed some day, but I doubt it would.
1)
[expr.type.conv]
A simple-type-specifier or typename-specifier followed by a parenthesized optional expression-list or by a braced-init-list (the initializer) constructs a value of the specified type given the initializer. [...]
If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression. [...]
2) (when T is of class type and such a constructor exists)
[class.ctor]/2
A constructor is used to initialize objects of its class type. Because constructors do not have names, they are never found during name lookup; however an explicit type conversion using the functional notation ([expr.type.conv]) will cause a constructor to be called to initialize an object.
it is possible to make an implicit reinterpret cast, undermining the type system.
ID wuff = ID(wau);
That's not an "implicit" reinterpret cast. That is an explicit type conversion. Although, the fact that the conversion does reinterpretation is indeed not easy to see. Specifically, the syntax of the cast is called "functional style".
If you're unsure what type of cast an explicit type conversion (whether using the functional syntax, or the C style syntax) performs, then you should refrain from using it. Many would argue that explicit type conversions should never be used.
If you had used static_cast instead, you would have stayed within the protection of the type system:
ID wuff = static_cast<ID>(wau);
error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'
It's often also safe to simply rely on implicit conversions:
ID wuff = wau;
error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'
Is this intended behaviour
Yes.
or a compiler bug?
No.
I had a perception that, type of a lambda is a function pointer. When I performed following test, I found it to be wrong (demo).
#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
assert(typeid(pFptr) == typeid(pAuto)); // assertion fails !
}
Is above code missing any point? If not then, what is the typeof a lambda expression when deduced with auto keyword ?
The type of a lambda expression is unspecified.
But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor. Anything inside the [] are turned into constructor parameters and members of the functor object, and the parameters inside () are turned into parameters for the functor's operator().
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer (MSVC2010 doesn't support this, if that's your compiler, but this conversion is part of the standard).
But the actual type of the lambda isn't a function pointer. It's some unspecified functor type.
It is a unique unnamed structure that overloads the function call operator. Every instance of a lambda introduces a new type.
In the special case of a non-capturing lambda, the structure in addition has an implicit conversion to a function pointer.
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]
The clause goes on to list varying properties of this type. Here are some highlights:
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
The consequence of this final passage is that, if you used a conversion, you would be able to assign LAMBDA to pFptr.
#include <iostream>
#include <typeinfo>
#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
std::cout<<typeid( *pAuto ).name() << std::endl;
std::cout<<typeid( *pFptr ).name() << std::endl;
std::cout<<typeid( pAuto ).name() << std::endl;
std::cout<<typeid( pFptr ).name() << std::endl;
}
The function types are indeed same, but the lambda introduces new type (like a functor).
It should also note that lambda is convertible to function pointer. However typeid<> returns a non-trvial object which should differ from lambda to generic function pointer. So the test for typeid<> is not a valid assumption. In general C++11 do not want us to worry about type specification, all that matter if a given type is convertible to a target type.
A practical solution from How can I store a boost::bind object as a class member?, try boost::function<void(int)> or std::function<void(int)>.
To further improve jalf's answer
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer
for example:
typedef int (*Foo)(int a);
auto bar = [](int a){
return a;
};
int tmp = 1;
auto bar2 = [tmp](int a){
return a+tmp;
};
Foo foo = bar; // this is ok
Foo foo2 = bar2; // this gives C/C++(413)
This might work:
h1 {
font-size:20px;
}
h2{
font-size:18px;
}
p {
font-size: 16px;
}
exmp{
font-size:16px;
color:#000077;
/*font-style: oblique;*/
font-family: Lucida Console;
}
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>
<h2>Step 1: </h2>
<p>Typedef a function pointer</p>
<exmp> typedef void(*FuncPointerType)();</exmp>
<p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>
I had a perception that, type of a lambda is a function pointer. When I performed following test, I found it to be wrong (demo).
#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
assert(typeid(pFptr) == typeid(pAuto)); // assertion fails !
}
Is above code missing any point? If not then, what is the typeof a lambda expression when deduced with auto keyword ?
The type of a lambda expression is unspecified.
But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor. Anything inside the [] are turned into constructor parameters and members of the functor object, and the parameters inside () are turned into parameters for the functor's operator().
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer (MSVC2010 doesn't support this, if that's your compiler, but this conversion is part of the standard).
But the actual type of the lambda isn't a function pointer. It's some unspecified functor type.
It is a unique unnamed structure that overloads the function call operator. Every instance of a lambda introduces a new type.
In the special case of a non-capturing lambda, the structure in addition has an implicit conversion to a function pointer.
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]
The clause goes on to list varying properties of this type. Here are some highlights:
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
The consequence of this final passage is that, if you used a conversion, you would be able to assign LAMBDA to pFptr.
#include <iostream>
#include <typeinfo>
#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
std::cout<<typeid( *pAuto ).name() << std::endl;
std::cout<<typeid( *pFptr ).name() << std::endl;
std::cout<<typeid( pAuto ).name() << std::endl;
std::cout<<typeid( pFptr ).name() << std::endl;
}
The function types are indeed same, but the lambda introduces new type (like a functor).
It should also note that lambda is convertible to function pointer. However typeid<> returns a non-trvial object which should differ from lambda to generic function pointer. So the test for typeid<> is not a valid assumption. In general C++11 do not want us to worry about type specification, all that matter if a given type is convertible to a target type.
A practical solution from How can I store a boost::bind object as a class member?, try boost::function<void(int)> or std::function<void(int)>.
To further improve jalf's answer
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer
for example:
typedef int (*Foo)(int a);
auto bar = [](int a){
return a;
};
int tmp = 1;
auto bar2 = [tmp](int a){
return a+tmp;
};
Foo foo = bar; // this is ok
Foo foo2 = bar2; // this gives C/C++(413)
This might work:
h1 {
font-size:20px;
}
h2{
font-size:18px;
}
p {
font-size: 16px;
}
exmp{
font-size:16px;
color:#000077;
/*font-style: oblique;*/
font-family: Lucida Console;
}
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>
<h2>Step 1: </h2>
<p>Typedef a function pointer</p>
<exmp> typedef void(*FuncPointerType)();</exmp>
<p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Recursive lambda functions in c++0x
Why can't I call a lambda recursively if I write it as:
auto a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a(); //recursive call
};
It gives compilation error (ideone):
prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function
prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer
What does the error mean?
I understand the reason why I can't write this:
auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'
We can't write this because the type of i has to be deduced from it's initialization, which means the type cannot be deduced if i itself appears in the initialization (ideone). But how does it matter in case of lambda? If I'm not wrong, the type of a lambda is determined by it's parameter(s) and the return type; it doesn't depend on the body if it returns nothing (in which case, the return type is deduced as void, irrespective of other statements in the lambda-body).
Anyway, I got a workaround, and I can use std::function instead as:
std::function<void()> a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a();
};
which compile fines (ideone). But I'm still interested to know the reason why the auto version doesn't compile.
The reason is that there is no special case for lambda-expression initializers of auto variables.
Such special cases would be prone to errors and misuses. You need to define the rules when you propose that something like a() should work. How is the operator() looked up? What is the precise state of a's type? Will the type be complete? (which implies that you already know the capture list of the lambda). Once you have formulated that in a format reasonable for a spec, it would be easier to make statements on it.
Allowing your use case would mean yet another case where you need to scan ahead in code, because to determine the type of a in a() you must be sure that the initializer ends with nothing that could "unlambda" the type
struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();
In this case, x() would call y::operator(), not the lambda.
As it is now, a is simply forbidden to be mentioned in its entire initializer. Because in C++, auto is not a type. It is merely a type specifier standing for a to-be-deduced type. As a consequence, an expression can never have type auto.
As I see it the important difference between the auto a case and the std::function<void()> a case is that the type std::function<void()> doesn't know/care about what the type of the real function it refers to really is. Writing:
std::function<void()> a;
is perfectly fine, where as:
auto a;
makes little sense. So when the time comes to synthesize the capture if you use std::function<void()> all that needs to be known about the type is already known, whereas with auto it's not yet known.
In a recursive function f is defined by f and return type of f is also determined by f in case of auto so it leads to infinite recursion.
when auto tries to derive a type. decltype(f()) will further deduce to another decltype(f)` as f derives to f e.g. a call on anything recursive is recursive too. return type determination turns recursive when applied on a recursive function. in a recursive function end of the recursion may be done on runtime. but determination is static only