Lambda Capture by Value forces an entire object with a const object

I was going to write a memorization pattern in C ++ and got the following approach

std::function<int(int)> Memoize(std::function<int(int)> fn) { std::map<int, int> memo; std::function<int(int)> helper = [=](int pos) { if (memo.count(pos) == 0) { memo[pos] = fn(pos); } return memo[pos]; }; return helper; } 

Strange, my VS 2012 compiler refused to compile with the following error

 1>Source1.cpp(24): error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const std::map<_Kty,_Ty>' (or there is no acceptable conversion) 

It seems to me that the compiler consciously captures everything by value as a const object. I cannot find a documented link to this behavior.

Can someone help me understand what is going on here?

+8
c ++ lambda c ++ 11 visual-c ++
source share
2 answers

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

[expr.prim.lambda]

5 The closure type for a nonequivalent lambda expression has an inline function call operator [...] This function call operator or operator template is declared const (9.3.1) if and only if the lambda expression parameter-declaration-sentence is not mutable .

Since the objects captured by the copy behave as if they are lambda member variables:

15 [...] For each object captured by the copy, an unnamed non-static data element is declared in the close type.

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

In a way, 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 lambda mutable as not const operator() , in your case lambda can be defined as follows:

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

To make the non-const lambda function, you need to add the mutable keyword:

 std::function<int(int)> Memoize(std::function<int(int)> fn) { std::map<int, int> memo; std::function<int(int)> helper = [=](int pos) mutable // <== HERE!! { if (memo.count(0) == 0) { memo[pos] = fn(pos); } return memo[pos]; }; return helper; } 
+6
source share

All Articles