कांस्ट सन्दर्भ के रूप में लाम्बा कब्जा?


166

क्या लंबर एक्सप्रेशन में कॉन्स्ट रेफरेंस द्वारा कैप्चर करना संभव है?

मैं उदाहरण के लिए नीचे दिए गए असाइनमेंट को विफल करना चाहता हूं:

#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string strings[] = 
    {
        "hello",
        "world"
    };
    static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);

    string best_string = "foo";

    for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
      {
        best_string = s; // this should fail
      }
    );
    return 0;
}

अद्यतन: चूंकि यह एक पुराना प्रश्न है, इसलिए इसे अद्यतन करने के लिए अच्छा हो सकता है यदि इसमें मदद करने के लिए C ++ 14 में सुविधाएं हैं। क्या C ++ 14 में एक्सटेंशन हमें कॉन्स्ट रेफरेंस द्वारा नॉन-कॉस्ट ऑब्जेक्ट को कैप्चर करने की अनुमति देते हैं? ( अगस्त 2015 )


क्या आपका लंबोदर जैसा नहीं दिखना चाहिए [&, &best_string](string const s) { ...}:?
इरजोट

3
वास्तव में असंगत कब्जा। "कॉन्स्ट एंड" बहुत उपयोगी हो सकता है जब आपके पास बड़ी कॉस्ट ऑब्जेक्ट होती है जिसे एक्सेस किया जाना चाहिए लेकिन लैम्ब्डा फ़ंक्शन में संशोधित नहीं किया गया है
सर्गटेक

कोड को देखते हुए। आप एक दो पैरामीटर लैंबडा का उपयोग कर सकते हैं और दूसरे को एक कॉन्स्टेंस रेफ़र के रूप में बाँध सकते हैं। हालांकि एक लागत के साथ आता है।
एलेक्स

1
यह C ++ 11 में संभव नहीं है, ऐसा प्रतीत होता है। लेकिन शायद हम इस सवाल को C ++ 14 के लिए अपडेट कर सकते हैं - क्या ऐसे एक्सटेंशन हैं जो इसकी अनुमति देते हैं? C ++ 14 सामान्यीकृत लैम्ब्डा कैप्चर करता है?
एरोन मैकडैड

जवाबों:


127

const n3092 के रूप में कैप्चर के लिए व्याकरण में नहीं है:

capture:
  identifier
  & identifier
  this

पाठ केवल कैप्चर-बाय-कॉपी और कैप्चर-बाय-रेफरेंस का उल्लेख करता है और किसी भी प्रकार के कॉन्स्ट-नेस का उल्लेख नहीं करता है।

मेरे लिए एक निरीक्षण जैसा लगता है, लेकिन मैंने मानकीकरण प्रक्रिया का बहुत बारीकी से पालन नहीं किया है।


47
मैंने बस एक बग को एक चर पर वापस ट्रैक किया था जिसे कैप्चर से संशोधित किया गया था जो कि परिवर्तनशील था, लेकिन होना चाहिए था const। या अधिक सही ढंग से, यदि कैप्चर वैरिएबल constहोता, तो कंपाइलर प्रोग्रामर पर सही व्यवहार लागू करता। वाक्यविन्यास का समर्थन किया जाए तो अच्छा होगा [&mutableVar, const &constVar]
सीन

ऐसा लगता है कि यह C ++ 14 के साथ संभव होना चाहिए, लेकिन मैं इसे काम नहीं कर सकता। कोई सुझाव?
एरोन मैकडैड

37
कब्जे को पकड़े गए चर से विरासत में मिला है। तो अगर आप के aरूप में कब्जा करना चाहते हैं const, const auto &b = a;लैम्ब्डा से पहले घोषणा और कब्जाb
StenSoft

7
@ सेनसेफ्ट ब्लायरघ। स्पष्ट रूप से छोड़कर यह तब लागू नहीं होता है जब संदर्भ द्वारा किसी सदस्य-चर को कैप्चर किया जाता है: [&foo = this->foo]किसी constफ़ंक्शन के अंदर मुझे यह कहते हुए एक त्रुटि मिलती है कि कैप्चर स्वयं क्वालिफायर को छोड़ देता है। यह जीसीसी 5.1 में एक बग हो सकता है, हालांकि, मुझे लगता है।
काइल स्ट्रैंड

119

में का उपयोग कर static_cast/ const_cast:

[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
    best_string = s; // fails
};

डेमो


में का उपयोग कर std::as_const:

[&best_string = std::as_const(best_string)](const string& s)
{
    best_string = s; // fails
};

डेमो २


इसके अलावा, शायद इसे स्वीकृत उत्तर में संपादित किया जाना चाहिए? किसी भी तरह से, एक अच्छा उत्तर होना चाहिए जो c ++ 11 और c ++ 14 दोनों को कवर करता है। हालांकि, मुझे लगता है कि यह तर्क दिया जा सकता है कि c ++ 14 आने वाले वर्षों में सभी के लिए पर्याप्त होगा
हारून मैकडैड

12
@AaronMcDaid const_castबिना शर्त ऑब्जेक्ट को एक कास्ट ऑब्जेक्ट (जब इसे कास्ट करने के लिए कहा जाता है const) में एक अस्थिर ऑब्जेक्ट को बदल सकता है , इस प्रकार, बाधाओं को जोड़ने के लिए मुझे पसंद हैstatic_cast
Piotr Skotnicki

1
दूसरी तरफ @PiotrSkotnicki, static_castयदि आप वास्तव में सही प्रकार नहीं मिला है, तो कॉन्स्ट रेफरेंस टू कॉन्स्ट रेफरेंस एक अस्थायी रूप से बना सकता है
MM

24
@MM &basic_string = std::as_const(best_string)सभी समस्याओं का समाधान करना चाहिए
पिओर Skotnicki

14
@PiotrSkotnicki उस समस्या को छोड़कर कुछ लिखने के लिए एक घृणित तरीका है जो सरल होना चाहिए const& best_string
काइल स्ट्रैंड

12

मुझे लगता है कि कैप्चर भाग को निर्दिष्ट नहीं किया जाना चाहिए const, क्योंकि कैप्चर का मतलब है, इसे केवल बाहरी गुंजाइश चर तक पहुंचने का एक तरीका चाहिए।

स्पेसियर बाहरी दायरे में बेहतर निर्दिष्ट है।

const string better_string = "XXX";
[&better_string](string s) {
    better_string = s;    // error: read-only area.
}

लंबो फंक्शन कांस्टेबल है (इसके दायरे में वैल्यू नहीं बदल सकता), इसलिए जब आप वैरिएबल को वैल्यू द्वारा कैप्चर करते हैं, तो वैरिएबल को नहीं बदला जा सकता है, लेकिन संदर्भ लैम्बडा स्कोप में नहीं है।


1
@ अमरनाथ बालसुब्रमणि: यह सिर्फ मेरी राय है, मुझे लगता है कि लंबोदर कैप्चर वाले हिस्से में एक कॉन्स्ट रेफरेंस निर्दिष्ट करने की कोई आवश्यकता नहीं है, यहां एक वैरिएबल कास्ट क्यों होना चाहिए और दूसरी जगह पर कॉन्स्टेबल नहीं है (यदि संभव हो तो, यह त्रुटि-प्रवण होगा )। वैसे भी आपकी प्रतिक्रिया देखकर खुश।
--b

2
यदि आपको better_stringयुक्त स्कोप के भीतर संशोधन करना है, तो यह समाधान काम नहीं करेगा। कॉन्स्ट-रे के रूप में कैप्चर करने के लिए उपयोग का मामला तब होता है जब वेरिएबल को सम्‍मिलित दायरे में परिवर्तनशील होना चाहिए, लेकिन लैम्‍ब्डा के भीतर नहीं।
जोनाथन शरमन

@JonathanSharman, एक चर का एक संदर्भ बनाने के लिए आपको कुछ भी खर्च नहीं करना है, इसलिए आप इसे बना सकते हैं const string &c_better_string = better_string;और ख़ुशी-ख़ुशी इसे [&c_better_string]
Steed

@Steed उस समस्या के साथ आप एक अतिरिक्त चर नाम को आसपास के दायरे में पेश कर रहे हैं। मुझे लगता है कि उपरोक्त पॉट्र स्कोटनिक का समाधान सबसे साफ है, क्योंकि यह चर स्कोप को न्यूनतम रखते हुए कब्ज को दूर करता है।
जोनाथन शरमन

@JonathanSharman, यहां हम राय की भूमि में प्रवेश करते हैं - सबसे सुंदर, या सबसे साफ, या जो भी हो। मेरा कहना यह है कि दोनों समाधान कार्य के लिए उपयुक्त हैं।
स्टीड

8

मुझे लगता है कि यदि आप फ़ चर के पैरामीटर के रूप में चर का उपयोग नहीं कर रहे हैं, तो आपको वर्तमान फ़ंक्शन के एक्सेस स्तर का उपयोग करना चाहिए। अगर आपको लगता है कि आपको नहीं करना चाहिए, तो अपने लंबो को इस फ़ंक्शन से अलग करें, यह इसका हिस्सा नहीं है।

वैसे भी, आप आसानी से उसी चीज़ को प्राप्त कर सकते हैं जो आप इसके बजाय किसी अन्य कॉन्स्टेंस संदर्भ का उपयोग करके चाहते हैं:

#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string strings[] = 
    {
        "hello",
        "world"
    };
    static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);

    string best_string = "foo";
    const string& string_processed = best_string;

    for_each( &strings[0], &strings[num_strings], [&string_processed]  (const string& s)  -> void 
    {
        string_processed = s;    // this should fail
    }
    );
    return 0;
}

लेकिन यह मानने के समान है कि आपके मेमने को वर्तमान फ़ंक्शन से अलग करना होगा, जिससे यह गैर-लंबा बन जाएगा।


1
कैप्चर क्लॉज में अभी भी best_stringकेवल उल्लेख है । इसके अलावा, जीसीसी 4.5 "इरादा की तरह कोड को सफलतापूर्वक अस्वीकार करता है"।
सेलिबिट्ज़

हां, इससे मुझे वे परिणाम मिलेंगे, जिन्हें मैं तकनीकी स्तर पर हासिल करने की कोशिश कर रहा था। अंततः, हालांकि, मेरे मूल प्रश्न का उत्तर "नहीं" है।
जॉन डिब्लिंग

वह इसे "नॉन-लैम्ब्डा" क्यों बनाएगा?

क्योंकि एक लंबोदर का स्वभाव संदर्भ-निर्भर है। यदि आपको किसी विशिष्ट संदर्भ की आवश्यकता नहीं है, तो यह एक मजेदार तरीका है। यदि फ़नकार को संदर्भ-स्वतंत्र होना चाहिए, तो इसे एक वास्तविक फ़नकार बनाएँ।
बजे

3
"Functor संदर्भ स्वतंत्र होना चाहिए, तो यह एक वास्तविक functor बनाने" ... और संभव इनलाइनिंग अलविदा चुंबन?
एंड्रयू लाजर

5

मुझे लगता है कि आपके पास तीन अलग-अलग विकल्प हैं:

  • कॉन्स्ट रेफरेंस का उपयोग न करें, लेकिन कॉपी कैप्चर का उपयोग करें
  • इस तथ्य को अनदेखा करें कि यह परिवर्तनीय है
  • std का उपयोग करें :: एक बाइनरी फ़ंक्शन के एक तर्क को बांधने के लिए बाध्य करें जिसमें एक कॉन्स्टेंस संदर्भ है।

एक प्रति का उपयोग करना

कॉपी कैप्चर के साथ लंबोदर के बारे में दिलचस्प बात यह है कि वे वास्तव में केवल पढ़े जाते हैं और इसलिए वास्तव में वही करते हैं जो आप उन्हें चाहते हैं।

int main() {
  int a = 5;
  [a](){ a = 7; }(); // Compiler error!
}

std का उपयोग :: बाँध

std::bindएक फंक्शन की कमता को कम करता है। हालांकि ध्यान दें कि यह फ़ंक्शन सूचक के माध्यम से अप्रत्यक्ष फ़ंक्शन कॉल कर सकता है।

int main() {
  int a = 5;
  std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}

1
चर दायरे में परिवर्तन को छोड़कर लंबोदर में परिलक्षित नहीं होगा। यह एक संदर्भ नहीं है, यह सिर्फ एक चर है जिसे पुन: असाइन नहीं किया जाना चाहिए क्योंकि पुनर्मूल्यांकन का मतलब यह नहीं होगा कि यह क्या प्रतीत होता है।
1


0

इस gcc बग के ठीक होने तक क्लैंग या प्रतीक्षा का उपयोग करें: बग 70385: लेम्पडा कैप्चर ऑफ़ कॉन्स्टेंस रेफ़रेंस विफल रहता है [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]


1
हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं। ”
डिव

ठीक है, मैंने यहाँ gcc बग विवरण जोड़ने के लिए अपना उत्तर संपादित किया।
user1448926

यह काफी अप्रत्यक्ष रूप से प्रश्न का उत्तर है, यदि कोई हो। बग इस बात के बारे में है कि किसी कॉन्सैप्ट को कैप्चर करते समय कंपाइलर कैसे फेल हो जाता है, इसलिए शायद सवाल में समस्या के बारे में पता करने या काम करने का कोई तरीका gcc के साथ काम नहीं कर सकता है।
Stein

0

एक का उपयोग करते हुए बस एल्गोरिथ्म होगा एल्गोरिथ्म ampersand यह मूल मूल्य के लिए स्ट्रिंग सेट है, दूसरे शब्दों में, लैम्बडा वास्तव में खुद को फ़ंक्शन के पैरामीटर के रूप में परिभाषित नहीं करेगा, हालांकि आसपास के दायरे में एक अतिरिक्त चर होगा ... इसे परिभाषित किए बिना। हालाँकि, यह स्ट्रिंग को विशिष्ट [&, और best_string] (स्ट्रिंग कास्ट s) के रूप में परिभाषित नहीं करेगा , इसलिए , इसका सबसे अच्छा संभावना है कि अगर हम इसे उस पर छोड़ दें, तो संदर्भ को कैप्चर करने की कोशिश कर रहे हैं।


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