C++0X Lambda Capture by Value Always Const

C++0x lambda capture by value always const?

Use mutable.


auto bar = [=] () mutable -> bool ....

Without mutable you are declaring the operator () of the lambda object const.

C++ lambda capture by value semantic?

You can add mutable qualifier.

auto testaaa = [testGetStr]() mutable {
// ^^^^^^^
acceptConstString(testGetStr.getString());
};

Otherwise the operator() of the lambda is const-qualified, and then can't call non-const member functions on the captured object.

  • mutable: allows body to modify the objects captured by copy, and to call their non-const member functions

Unless the keyword mutable was used in the lambda-expression, the
function-call operator is const-qualified and the objects that were
captured by copy are non-modifiable from inside this operator().

PS: Or better to make TestGetStr::getString() const member function.

Lambda Capture by Value forces all scoped object to const

Lambdas behave more or less like function objects; like a function object they have a function call operator, i.e. operator(). For non-mutable lambdas, this function is const:

[expr.prim.lambda]

5 The closure type for a non-generic lambda-expression has a public
inline function call operator [...] This function call operator or
operator template is declared const
(9.3.1) if and only if the
lambda-expression’s parameter-declaration-clause is not followed by
mutable
.

Because entities captured by copy behave as though they were member variables of the lambda:

15 [...] For each entity captured by copy, an unnamed non-static data member is declared in the closure type.

and non-mutable members cannot be modified inside a const member function ([class.this] / 1, [dcl.type.cv] / 4), if you want to modify the captured entities you will have to declare a mutable lambda.

As it stands your lambda looks like this:

class Helper
{
public:
int operator()(int) const;
private:
std::map<int, int> memo;
std::function<int(int)> fn;
};

You can think of a mutable lambda as having a non-const operator(), in your case the lambda can be defined as follows:

std::function<int(int)> helper = [=](int pos) mutable
// etc

Why does C++11's lambda require mutable keyword for capture-by-value, by default?

It requires mutable because by default, a function object should produce the same result every time it's called. This is the difference between an object orientated function and a function using a global variable, effectively.

Binding a const function reference to a lambda

As mentioned already, a capture-less lambda is convertible to a function pointer. So if you want to bind that static function to a reference, you need to dereference the pointer.

int(&foo)(int, int) = *[](int a, int b) { return a + b; };

Applying * to the lambda causes a bunch of machinery to kick in. Since the lambda doesn't overload operator*, but does implement a conversion to a pointer type, that conversion happens. Afterwards * is applied to the returned pointer and that yields a function lvalue. That lvalue can then bind to the reference.

Here it is live.

Return local variable to const ref from lambda

Your lambda returns a prvalue, so the call expression is a temporary object, whose lifetime is extended because it is bound to a reference.

The situation is entirely analogous to the following, simpler example:

int f() { return 12; }

const int& a = f();

Here a is bound to a temporary object of type int and value 12.

If you do not specify the return type of a lambda, the return type is always either void or an object type. If you want your lambda to return an lvalue or xvalue, you will explicitly need to specify the return type, e.g. as -> int&, -> auto&, -> decltype(auto), etc.

const static auto lambda used with capture by reference

A static function-scope variable is initialised "lazily," when control flow first reaches its declaration. This means that the capture by reference does indeed bind to the foo currently on stack, and when the call terminates, that binding becomes dangling.

Don't try to help the compiler too much; making lambda static looks like a micro-optimisation, with very bad side effects. There's next to no overhead involved in actually creating a closure object, and the compiler can easily inline it regardless of whether it's static or not.

Not to mention the fact that you're not saving on creating the std::function object even with your approach. The type of a lambda expression is an unnamed closure object, not std::function. So even if lambda is static, the std::function object is created in each call anyway (unless the whole thing is inlined).



Related Topics



Leave a reply



Submit