I'm trying to capture a const object via copy in a (mutable) lambda. My compiler however complains, that the captured object is const.
Should it not be possible to copy the object as non-const?
struct Foo
{
Foo(){}
void Func(){}
};
int main()
{
const Foo foo;
[foo]() mutable { foo.Func(); };
}
Compiling with g++ 4.7.2:
testcase.cpp: In lambda function:
testcase.cpp:10:29: error: no matching function for call to ‘Foo::Func() const’
testcase.cpp:10:29: note: candidate is:
testcase.cpp:4:7: note: void Foo::Func() <near match>
testcase.cpp:4:7: note: no known conversion for implicit ‘this’ parameter from ‘const Foo*’ to ‘Foo*’
Compiling with clang++ 3.1:
testcase.cpp:10:20: error: member function 'Func' not viable: 'this' argument has type 'const Foo', but function is not marked const
std::async([foo]() mutable { foo.Func(); });
The Standard document (or rather the draft...) defines in 5.1.2.14 that "The type [...] is the type of the corresponding captured entity", so I guess that would include the cv-specifiers.
It does not seem intuitive though.
First, the type of a lambda expression, which has capture, is a class type (5.1.2 Lambda expressions [expr.prim.lambda] #3)
That type has an operator()
which is by default const
, unless mutable
is used in the lambda expression ([expr.prim.lambda] #5)
Next, for each entity captured as copy, a unnamed member is declared in the closure type. [expr.prim.lambda] #14]
If you explicitly build the (mostly) equivalent of the capture type, everything will naturally follow from the usual semantics for classes, const-qualified types and const qualified member functions.
Example:
struct S
{
void f();
void fc() const;
};
void g()
{
S s0;
// [s0] () { s0.f(); }; // error, operator() is const
[s0] () { s0.fc(); }; // OK, operator() is const, S::fc is const
[s0] () mutable { s0.f(); };
[s0] () mutable { s0.fc(); };
const S s1;
// [s1] () { s1.f(); }; // error, s1 is const, no matter if operator() is const
[s1] () { s1.fc(); };
// [s1] () mutable { s1.f(); }; // error, s1 is const, no matter if operator() is const
[s1] () mutable { s1.fc(); };
}
I guess the confusion stems from the fact that mutable
in the lambda-declarator concerns the const
-ness of the operator()
, not the mutable
-ility of the data members of the closure type. It would be more natural to use const
, as with member functions, but I guess the standards committee wanted const
to be the default.
This will work under C++14, not a solution for C++11.
struct Foo
{
Foo(){}
void Func(){}
};
int main()
{
const Foo foo;
[foo = foo]() mutable { foo.Func(); };
}
But I don't really understand why [foo]
keeps the const but [foo = foo]
not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With