5

I've been using c++ 0x for a while now and have been very much enjoying the new lamba function facilities. I've become accustomed to specifying [=] in my lambda declarations to indicate that I want to pass externally scoped variables into my lambda by value.

However, today I came accross a very strange lambda issue. I've noticed that passing an externally scoped map into a lamba by value during a for_each works oddly. Here's an example which shows the issue:

void LambdaOddnessOne ()
{
    map<int, wstring> str2int;
    str2int.insert(make_pair(1, L"one"));
    str2int.insert(make_pair(2, L"two"));

    vector<int> numbers;
    numbers.push_back(1);
    numbers.push_back(2);

    for_each ( numbers.begin(), numbers.end(), [=]( int num ) 
    {
        //Calling find() compiles and runs just fine
        if (str2int.find(num) != str2int.end())
        {
            //This won't compile... although it will outside the lambda
            str2int[num] = L"three";

            //Neither will this saying "4 overloads have no legal conversion for 'this' pointer"
            str2int.insert(make_pair(3, L"three"));
        }
    });

}

Many of map's methods could be called from inside the lamba (find for example) but lots of other methods resulted in compile errors when they'd compile just fine outside the lamba.

Attempting to use the [ operator for example resulted in:

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)

Attempting to use the .insert function resulted in:

error C2663: 'std::_Tree<_Traits>::insert' : 4 overloads have no legal conversion for 'this' pointer

Does anyone understand this inconsistent behavior? Is it just an issue with the MS compiler? I haven't tried any others.

Benj
  • 31,668
  • 17
  • 78
  • 127

2 Answers2

7

FYI [=] captures by value, IIRC [&] captures by reference.

http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/cpp/lin/cref_cls/common/cppref_lambda_lambdacapt.htm#cppref_lambda_lambdacapt

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

Community
  • 1
  • 1
RedX
  • 14,749
  • 1
  • 53
  • 76
  • Whoops, yes, had a bit of a mind melt there... And my example does indeed work when passed by reference... Although this does raise the question, why can't a map be passed in by value? – Benj Jun 08 '11 at 15:14
  • 7
    @Benj: It can be passed in by value. You just can't modify it, because the value becomes a member of the lambda, and lambdas are const by default. If you want to modify it, declare it mutable. i.e. `[=]( int num ) mutable { }` – Benjamin Lindley Jun 08 '11 at 15:17
  • Ahaha, interesting! Yes that does explain it. I've edited my original question to reflect the fact that I was passing by value. Thanks guys :-) – Benj Jun 08 '11 at 15:20
4

By default, a lambda's function call operator is const (so you cannot modify the map that is passed by value), but you can make it non-const by writing mutable:

for_each ( numbers.begin(), numbers.end(), [=]( int num ) mutable
{
    // ...

For more information, see why does C++0x's lambda require “mutable” keyword for capture-by-value, by default?

Community
  • 1
  • 1
Bradley Grainger
  • 27,458
  • 4
  • 91
  • 108