क्या मैं एक सीमा ऑपरेशन के लिए एक अस्थायी पाइप लौटा सकता हूं?


9

मान लीजिए कि मेरे पास एक generate_my_rangeवर्ग है जो मॉडल range(विशेष रूप से, है regular)। फिर निम्नलिखित कोड सही है:

auto generate_my_range(int some_param) {    
  auto my_transform_op = [](const auto& x){ return do_sth(x); };
  return my_custom_rng_gen(some_param) | ranges::views::transform(my_transform_op);
}
auto cells = generate_my_range(10) | ranges::to<std::vector>;

है my_custom_rng_gen(some_param)(प्रथम) पाइप ऑपरेटर द्वारा मूल्य द्वारा उठाए गए, या मैं एक झूलते संदर्भ है एक बार मैं छोड़ generate_my_rangeगुंजाइश?

क्या यह फ़ंक्शननल कॉल के साथ भी ऐसा ही होगा ranges::views::transform(my_custom_rng_gen(some_param),my_transform_op)?

क्या यह सही होगा यदि मैंने एक लैवल्यू संदर्भ का उपयोग किया है? उदाहरण के लिए:

auto generate_my_range(int some_param) {
  auto my_transform_op = [](const auto& x){ return do_sth(x); };
  auto tmp_ref = my_custom_rng_gen(some_param);
  return tmp_ref | ranges::views::transform(my_transform_op);
}

यदि इन परिचालनों के लिए मानों को श्रेणी में लिया जाता है, तो यदि मैं एक कंटेनर में एक लैवल्यू रेफ पास करता हूं तो मुझे क्या करना चाहिए? क्या मुझे एक ranges::views::all(my_container)पैटर्न का उपयोग करना चाहिए ?


क्या my_custom_rng_gen (some_param) पहले से ही बाध्य है? क्या आप का मतलब कुछ ऐसा है जैसे कि Godbolt.org/z/aTF8RN बिना टेक (5) के?
पोर्शे 9II

@ Porsche9II हाँ यह एक सीमाबद्ध सीमा है। मान लीजिए कि यह एक कंटेनर है
बेयरेंजर

जवाबों:


4

रेंज लाइब्रेरी में दो तरह के ऑपरेशन होते हैं:

  • वे दृश्य जो आलसी हैं और अंतर्निहित कंटेनर की आवश्यकता है।
  • वे क्रियाएं जो उत्सुक हैं, और परिणामस्वरूप नए कंटेनर का उत्पादन करती हैं (या मौजूदा लोगों को संशोधित करती हैं)

दृश्य हल्के हैं। आप उन्हें मूल्य से पास करते हैं और अंतर्निहित कंटेनर को वैध और अपरिवर्तित रहने की आवश्यकता होती है।

से पर्वतमाला-v3 प्रलेखन

एक दृश्य एक हल्का आवरण होता है जो तत्वों के अंतर्निहित अनुक्रम को किसी कस्टम तरीके से म्यूट या कॉपी किए बिना प्रस्तुत करता है। दृश्य बनाना और कॉपी करना और गैर-संदर्भ संदर्भ शब्दार्थ के लिए सस्ते हैं।

तथा:

अंतर्निहित रेंज पर कोई भी ऑपरेशन जो इसके पुनरावृत्तियों या प्रहरी को अमान्य करता है, उस सीमा के किसी भी हिस्से को संदर्भित करने वाले किसी भी दृश्य को अमान्य कर देगा।

अंतर्निहित कंटेनर का विनाश स्पष्ट रूप से सभी पुनरावृत्तियों को अमान्य करता है।

आपके कोड में आप विशिष्ट रूप से विचारों का उपयोग कर रहे हैं - आप उपयोग करते हैं ranges::views::transform। पाइप महज एक वाक्य रचना चीनी है जो इसे लिखने के तरीके को आसान बनाता है। आपको पाइप में आखिरी चीज को देखना चाहिए जो आप पैदा करते हैं - आपके मामले में, यह एक दृश्य है।

यदि कोई पाइप ऑपरेटर नहीं था, तो यह संभवतः कुछ इस तरह दिखाई देगा:

ranges::views::transform(my_custom_rng_gen(some_param), my_transform_op)

अगर इस तरह से कई परिवर्तन जुड़े थे तो आप देख सकते हैं कि यह कितना बदसूरत हो जाएगा।

इस प्रकार, अगर my_custom_rng_genकिसी प्रकार के कंटेनर का उत्पादन होता है, जिसे आप बदल देते हैं और फिर वापस लौट जाते हैं, तो वह कंटेनर नष्ट हो जाता है और आपके विचार से संदर्भ खतरे में पड़ जाते हैं। अगर my_custom_rng_genएक अन्य कंटेनर के लिए एक दृश्य है जो इन scopes के बाहर रहता है, तो सब कुछ ठीक है।

हालांकि, कंपाइलर को यह पहचानने में सक्षम होना चाहिए कि आप एक अस्थायी कंटेनर पर एक दृश्य लागू कर रहे हैं और एक संकलन त्रुटि के साथ आपको मारा।

यदि आप चाहते हैं कि आपका फ़ंक्शन किसी श्रेणी के कंटेनर के रूप में वापस आए, तो आपको परिणाम को स्पष्ट रूप से "भौतिक" करने की आवश्यकता है। उसके लिए, ranges::toफ़ंक्शन के भीतर ऑपरेटर का उपयोग करें ।


अपडेट: आपकी टिप्पणी के बारे में अधिक प्रासंगिक होने के लिए "प्रलेखन कहां कहता है कि कंपोजिंग रेंज / पाइपिंग एक दृश्य लेता है और संग्रहीत करता है?"

पाइप केवल चीजों को आसानी से पढ़े जाने वाले अभिव्यक्ति में जोड़ने के लिए एक वाक्यविन्यास चीनी है। यह कैसे उपयोग किया जाता है पर निर्भर करता है, यह एक दृश्य वापस कर सकता है या नहीं। यह राइट-हैंड साइड तर्क पर निर्भर करता है। आपके मामले में यह है:

`<some range> | ranges::views::transform(...)`

इसलिए अभिव्यक्ति जो भी views::transformलौटाती है।

अब, परिवर्तन के प्रलेखन को पढ़कर:

नीचे आलसी श्रेणी के कॉम्बिनेटरों या विचारों की एक सूची दी गई है, जो कि रेंज-वी 3 प्रदान करता है, और एक ब्लर का उपयोग कैसे किया जाता है, इसके बारे में बताया गया है।

[...]

views::transform

एक स्रोत रेंज और एक unary फ़ंक्शन को देखते हुए, एक नई श्रेणी लौटाएं जहां प्रत्येक परिणाम तत्व एक स्रोत तत्व के लिए unary फ़ंक्शन को लागू करने का परिणाम है।

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


ठीक है। मेरे लिए थोड़ा रहस्यमय है फिर भी यह कैसे काम करता है जब मैं एक कंटेनर को पाइप से गुजरता हूं (अर्थात रचना द्वारा बनाई गई रेंज ऑब्जेक्ट)। इसे किसी तरह कंटेनर के दृश्य को संग्रहीत करने की आवश्यकता है। के साथ किया जाता है ranges::views::all(my_container)? और क्या होगा अगर एक दृश्य पाइप को पारित किया जाता है? क्या यह पहचानता है कि यह एक कंटेनर या एक दृश्य है? क्या इसकी जरूरत है? कैसे?
बेयरेंगर

"कंपाइलर को यह पहचानने में सक्षम होना चाहिए कि आप एक अस्थायी कंटेनर पर एक दृश्य लागू कर रहे हैं और एक संकलन त्रुटि के साथ आपको मार रहे हैं" यही मैंने भी सोचा था: यदि मैं कुछ बेवकूफी करता हूं, तो इसका मतलब है कि प्रकार पर एक अनुबंध (बाएं होना) मान) पूरा नहीं हुआ है। सामान जैसे कि रेंज- v3 द्वारा किया जाता है। लेकिन इस मामले में कोई समस्या नहीं है। यह संकलन और चलाता है। इसलिए अपरिभाषित व्यवहार हो सकता है, लेकिन यह दिखाई नहीं देता है।
बैरेंजर

यह सुनिश्चित करने के लिए कि यदि आपका कोड दुर्घटना से सही है या सब कुछ ठीक है तो मुझे इसकी सामग्री देखने की आवश्यकता होगी my_custom_rng_gentransformहूड के नीचे पाइप और इंटरैक्ट कितना महत्वपूर्ण है, यह महत्वपूर्ण नहीं है। पूरी अभिव्यक्ति एक तर्क (एक कंटेनर या कुछ कंटेनर के लिए एक दृश्य) के रूप में एक सीमा लेता है और उस कंटेनर को एक अलग दृश्य देता है। रिटर्न मान कभी भी कंटेनर का मालिक नहीं होगा, क्योंकि यह एक दृश्य है।
साइग्नसएक्स 1

1

रेंज- v3 प्रलेखन से लिया गया :

दृश्य [...] गैर-संदर्भ संदर्भ शब्दार्थ है।

तथा

सिंगल रेंज ऑब्जेक्ट होने से संचालन की पाइपलाइनों की अनुमति मिलती है। एक पाइपलाइन में, एक सीमा किसी प्रकार से आलसी रूप से अनुकूलित या उत्सुक रूप से उत्परिवर्तित होती है, जिसके परिणाम तुरंत आगे अनुकूलन या उत्परिवर्तन के लिए उपलब्ध होते हैं। आलसी अनुकूलन विचारों द्वारा नियंत्रित किया जाता है, और उत्सुक उत्परिवर्तन क्रियाओं द्वारा नियंत्रित किया जाता है।

// taken directly from the the ranges documentation
std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace ranges;
auto rng = vi | views::remove_if([](int i){ return i % 2 == 1; })
              | views::transform([](int i){ return std::to_string(i); });
// rng == {"2","4","6","8","10"};

ऊपर दिए गए कोड में, आरएनजी बस अंतर्निहित डेटा और फ़िल्टर और परिवर्तन कार्यों के लिए एक संदर्भ संग्रहीत करता है। Rng के iterated होने तक कोई काम नहीं किया जाता है।

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

दूसरे शब्दों में, आपको यह सुनिश्चित करने की आवश्यकता है कि अंतर्निहित सीमा दृश्य को रेखांकित करती है, या आप मुसीबत में हैं।


हां, विचार गैर-स्वामित्व वाले हैं, लेकिन दस्तावेज कहां कहता है कि कंपोजिंग रेंज / पाइपिंग एक दृश्य लेता है और संग्रहीत करता है? यह संभव हो सकता है (और मुझे लगता है, एक अच्छी बात है) निम्न नीति है: मूल्य द्वारा स्टोर करें यदि रेंज एक प्रतिद्वंद्वी संदर्भ द्वारा दी गई है।
बैरेंजर

1
@ Bérenger I ने रेंज डॉक्यूमेंटेशन से थोड़ा और जोड़ा। लेकिन वास्तव में बात यह है: एक दृष्टिकोण गैर-मालिक है । यह परवाह नहीं करता है कि आप इसे एक प्रतिद्वंद्विता सौंपते हैं।
रूम्बूरक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.