208 votes

Utilisation d'une variable membre dans une liste de capture lambda à l'intérieur d'une fonction membre

Le code suivant se compile avec gcc 4.5.1 mais pas avec 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;
}

Voici l'erreur :

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

Donc,

1> Quel est le bon compilateur ?

2> Comment puis-je utiliser des variables membres à l'intérieur d'un lambda dans VS2010 ?

1 votes

Note : Il devrait être pair<const int, set<int> > c'est le type de paire actuel d'une carte. Il peut également s'agir d'une référence à une constante.

0 votes

Relatif ; très utile : thispointer.com/

203voto

Trass3r Points 1505

Résumé des alternatives :

capture this :

auto lambda = [this](){};

utiliser une référence locale au membre :

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

exemple : https://godbolt.org/g/dEKVGD

197voto

Xeo Points 69818

Je pense que VS2010 est correct cette fois-ci, et je vérifierais si j'avais la norme à portée de main, mais actuellement je ne l'ai pas.

Maintenant, c'est exactement comme le dit le message d'erreur : Vous ne pouvez pas capturer des choses en dehors de la portée de la lambda. † grid n'est pas dans la portée englobante, mais this est (chaque accès à grid se produit en fait comme this->grid dans les fonctions membres). Pour votre cas d'utilisation, la capture this fonctionne, puisque vous l'utiliserez tout de suite et que vous ne voulez pas copier le fichier grid

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

Si toutefois, vous souhaitez stocker la grille et la copier pour y accéder ultérieurement, où votre puzzle peut être déjà détruit, vous devrez faire une copie intermédiaire, locale :

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

† Je simplifie - cherchez sur Google "reaching scope" ou consultez le §5.1.2 pour tous les détails sanglants.

1 votes

Cela me semble assez limité. Je ne comprends pas pourquoi un compilateur aurait besoin d'empêcher une telle chose. Cela fonctionne bien avec bind, bien que la syntaxe soit horrible avec l'opérateur de décalage à gauche d'ostream.

3 votes

Pourrait tmp être un const & a grid pour réduire le nombre de copies ? Nous voulons toujours au moins une copie, la copie dans le lambda ( [tmp] ), mais pas besoin d'une deuxième copie.

4 votes

Cette solution pourrait créer une copie supplémentaire inutile de grid bien qu'elle soit probablement optimisée. Plus court et meilleur c'est : auto& tmp = grid; etc.

23voto

Je crois que vous devez capturer this .

1 votes

C'est correct, cela capturera le pointeur this et vous pourrez toujours vous référer à grid directement. Le problème est que si vous voulez copier la grille, que faire ? Cela ne vous permettra pas de le faire.

10 votes

Vous pouvez, mais seulement d'une manière détournée : vous devez faire une copie locale, et capturer que dans le lambda. C'est juste la règle avec les lambdas, vous ne pouvez pas capturer de raideur en dehors de la portée englobante.

0 votes

Bien sûr, vous pouvez copier. Je voulais dire que vous ne pouvez pas le copier-capturer, bien sûr.

16voto

dlanod Points 2597

Une méthode alternative qui limite le champ d'application de la lambda plutôt que de lui donner accès à l'ensemble des données. this est de passer dans une référence locale à la variable membre, par ex.

auto& localGrid = grid;
int i;
for_each(groups.cbegin(),groups.cend(),[localGrid,&i](pair<int,set<int>> group){
            i++;
            cout<<i<<endl;
   });

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X