Benj
Benj

Reputation: 32398

Why does std::map behave strangely when passed by value into a lambda?

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.

Upvotes: 5

Views: 2485

Answers (2)

Bradley Grainger
Bradley Grainger

Reputation: 28172

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?

Upvotes: 4

Related Questions