Использование переменной-члена в лямбда-списке захвата внутри функции-члена - PullRequest
120 голосов
/ 26 октября 2011

Следующий код компилируется с gcc 4.5.1, но не с 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;
        });
}
int main()
{
        return 0;
}

Это ошибка:

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> какой компилятор прав?

2> Как я могу использовать переменные-члены внутри лямбды в VS2010?

Ответы [ 5 ]

133 голосов
/ 26 октября 2011

Я полагаю, что VS2010 на этот раз прав, и я бы проверил, был ли у меня под рукой стандарт, но в настоящее время я не могу.

Теперь, точно так же, как в сообщении об ошибке говорится: «Вы можете»• захватывать вещи вне области охвата лямбды. grid не входит в область охвата, но this есть (каждый доступ к grid фактически происходит как this->grid в функциях-членах).Для вашего варианта использования захват this работает, так как вы будете использовать его сразу и не хотите копировать grid

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

Если, однако, вы хотите сохранить сетку и скопироватьэто для последующего доступа, где ваш puzzle объект может быть уже уничтожен, вам нужно будет сделать промежуточную локальную копию:

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

† Я упрощаю - Google для "достиженияобласть "или см. §5.1.2 для всех кровавых деталей.

73 голосов
/ 03 февраля 2017

Сводка альтернатив:

захват this:

auto lambda = [this](){};

использовать локальную ссылку на член:

auto& tmp = grid;
auto lambda = [ tmp](){}; // capture grid by (a single) copy
auto lambda = [&tmp](){}; // capture grid by ref

C ++14:

auto lambda = [ grid = grid](){}; // capture grid by copy
auto lambda = [&grid = grid](){}; // capture grid by ref

пример: https://godbolt.org/g/dEKVGD

20 голосов
/ 26 октября 2011

Полагаю, вам нужно захватить this.

13 голосов
/ 29 октября 2015

Альтернативный метод, который ограничивает область действия лямбды, а не дает ей доступ ко всему this, заключается в передаче локальной ссылки на переменную-член, например,

auto& localGrid = grid;
int i;
for_each(groups.cbegin(),groups.cend(),[localGrid,&i](pair<int,set<int>> group){
            i++;
            cout<<i<<endl;
   });
0 голосов
/ 20 марта 2019

Чтобы использовать переменные-члены внутри лямбда-выражения в VS2010 и т. Д., Вам нужно захватить этот указатель в списке захвата.

Пожалуйста, обратитесь ниже образец кода:

class A
{
    public:
    std::map<string, TicketInfo>  m_mapImanFileUIDTicket;
    void Myfunction();
};

void A::Myfunction()
{
    std::string Filename;
    NameRef namedRefOutput;

    auto lambdaGetReadTicket = [FileName, namedRefOutput, this]()
    {
        TicketInfo      Info;
        Info.fileName = FileName;
        Info.ticket = namedRefOutput.ticket;
        m_mapImanFileUIDTicket[FileName] = Info; //This member variable defined in class
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...