एक सदस्य समारोह के अंदर लंबो कैप्चर सूची में सदस्य चर का उपयोग करना


145

निम्नलिखित कोड 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 में एक लैम्ब्डा के अंदर सदस्य चर का उपयोग कैसे कर सकता हूं?


1
नोट: यह होना चाहिए pair<const int, set<int> >, कि नक्शे का वास्तविक जोड़ी-प्रकार है। यह संभवतः एक संदर्भ-से-कॉन्स्टेबल भी होना चाहिए।
Xeo

सम्बंधित; बहुत मददगार: itpointer.com/…
गेब्रियल स्टेपल्स

जवाबों:


157

मुझे विश्वास है कि इस बार VS2010 सही होगा, और मैं जांच करूंगा कि क्या मेरे पास मानक काम था, लेकिन वर्तमान में मैं नहीं।

अब, यह ठीक उसी तरह है जैसे त्रुटि संदेश कहता है: आप लैम्ब्डा के घेरने के दायरे के बाहर सामान को नहीं पकड़ सकते। grid एन्क्लोजिंग दायरे में नहीं है, लेकिन thisहै ( gridवास्तव this->gridमें सदस्य कार्यों के रूप में होता है)। अपने usecase के लिए, कैप्चरिंग 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 या सभी gory विवरणों के लिए .25.1.2 देखें।


1
यह मुझे काफी सीमित लगता है। मुझे समझ में नहीं आता है कि एक संकलक को ऐसी चीज़ को रोकने की आवश्यकता क्यों होगी। यह बाइंड के साथ अच्छी तरह से काम करता है, हालांकि सिंटैक्स ओस्ट्रीम लेफ्ट शिफ्ट ऑपरेटर के साथ भयानक है।
जीन-साइमन ब्रोचू

3
कर सके tmpएक होना const &करने के लिए gridकॉपी करने में कटौती करने के लिए? हम अभी भी कम से कम एक प्रति चाहते हैं, प्रतिलिपि लंबोदर ( [tmp]) में है, लेकिन दूसरी प्रति की कोई आवश्यकता नहीं है।
एरॉन मैकडैड

4
समाधान एक अनावश्यक अतिरिक्त प्रतिलिपि बना सकता है, gridहालांकि यह संभवतः अनुकूलित हो जाता है। कम और बेहतर है: auto& tmp = grid;आदि
टॉम स्विरली

4
यदि आपके पास C ++ 14 उपलब्ध है, तो आप [grid = grid](){ std::cout << grid[0][0] << "\n"; }
सिगई

यह gcc 4.9 (और उस बात के लिए gcc 5.4) में तय किया गया प्रतीत होता हैerror: capture of non-variable ‘puzzle::grid’
बीजीबोर

108

विकल्पों का सारांश:

कब्जा this:

auto lambda = [this](){};

सदस्य को स्थानीय संदर्भ का उपयोग करें:

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

सी ++ 14:

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

उदाहरण: https://godbolt.org/g/dEKVGD


5
दिलचस्प है कि इसके लिए शुरुआती सिंटैक्स कार्यों के साथ कैप्चर का केवल स्पष्ट उपयोग (यानी C ++ 14 में अभी [&grid]भी काम नहीं कर रहा है)। यह जानकर बहुत खुशी हुई!
15

1
अच्छा सारांश। मुझे C ++ 14 सिंटैक्स बहुत सुविधाजनक लगता है
टुकट

22

मेरा मानना ​​है, आपको कब्जा करने की जरूरत है this


1
यह सही है, यह इस पॉइंटर को कैप्चर करेगा और आप अभी भी gridसीधे संदर्भित कर सकते हैं। समस्या यह है कि अगर आप ग्रिड की नकल करना चाहते हैं तो क्या होगा? यह आपको ऐसा करने की अनुमति नहीं देगा।
Xeo

9
आप कर सकते हैं, लेकिन केवल एक राउंडअबाउट तरीके से: आपको एक स्थानीय प्रतिलिपि बनानी होगी, और उस लंबोदर में कब्जा करना होगा । लैंबडास के साथ बस यही नियम है, आप संलग्नक दायरे के बाहर कठोर कब्जा नहीं कर सकते।
Xeo

ज़रूर आप कॉपी कर सकते हैं। मेरा मतलब था कि आप इसे कॉपी-कैप्चर नहीं कर सकते, बेशक।
माइकल क्रेलिन -

मैंने जो वर्णन किया है वह इंटरमीडिएट स्थानीय कॉपी के माध्यम से एक कॉपी कैप्चर करता है - मेरा उत्तर देखें। उस के अलावा, मैं एक सदस्य चर पर कब्जा कॉपी करने के लिए कोई रास्ता नहीं जानता।
Xeo

ज़रूर, यह कॉपी कैप्चर करता है, लेकिन सदस्य नहीं। इसमें दो प्रतियाँ शामिल हैं जब तक कि संकलक सामान्य से अधिक स्मार्ट न हो, मुझे लगता है।
माइकल क्रेलिन -

14

एक वैकल्पिक विधि जो लंबो के दायरे को सीमित करती है, बल्कि इसे पूरे तक पहुंच देने के बजाय thisसदस्य चर के स्थानीय संदर्भ में पारित करना है, जैसे।

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

मुझे आपके विचार से प्यार है: एक नकली संदर्भ चर का उपयोग करना और सूची पर कब्जा करने के लिए इसे पास करना :)
Emadpres
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.