Copied const object in lambda closure not mutable

c++, c++11, lambda

Solution

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.

Problem

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.

Original source