Search code examples
c++visual-studio-2010lambdac++11

Using data member in lambda capture list inside a member function


The following code compiles with gcc 4.5.1 but not with VS2010 SP1:

#include <iostream>
#include <vector>
#include <map>
#include <utility>
#include <set>
#include <algorithm>
 
using namespace std;
class puzzle
{
    vector<vector<int>> grid;
    map<int,set<int>> groups;
public:
    int member_function();
};
 
int puzzle::member_function()
{
    int i;
    for_each(groups.cbegin(), groups.cend(), [grid, &i](pair<int,set<int>> group) {
        i++;
        cout << i << endl;
    });
}

This is the error:

error C3480: 'puzzle::grid': a lambda capture variable must be from an enclosing function scope
warning C4573: the usage of 'puzzle::grid' requires the compiler to capture 'this' but the current default capture mode does not allow it
  1. Which compiler is right?
  2. How can I use data members inside a lambda in VS2010?

Solution

  • I believe VS2010 to be right this time, and I'd check if I had the standard handy, but currently I don't.

    Now, it's exactly like the error message says: You can't capture stuff outside of the enclosing scope of the lambda. grid is not in the enclosing scope, but this is (every access to grid actually happens as this->grid in member functions). For your usecase, capturing this works, since you'll use it right away and you don't want to copy the grid

    auto lambda = [this](){ std::cout << grid[0][0] << "\n"; }
    

    If however, you want to store the grid and copy it for later access, where your puzzle object might already be destroyed, you'll need to make an intermediate, local copy:

    vector<vector<int> > tmp(grid);
    auto lambda = [tmp](){}; // capture the local copy per copy
    

    † I'm simplifying - Google for "reaching scope" or see §5.1.2 for all the gory details.