दिलचस्प पोस्ट
डबल परिशुद्धता – दशमलव स्थान मैं नए टैब में एक लिंक कैसे खोल सकता हूं (और नई विंडो नहीं)? पटरियों में to_json ओवरराइड करने के लिए कैसे? अनुपयुक्त जावा एचटीटीपी क्लाइंट – यह कितना मुश्किल हो सकता है? सूची से आइटम को हटाने का बुद्धिमान तरीका <T> जबकि सी # में एन्यूमरेटिंग किसी भीड़-भाड़ वाले सॉर्ट के साथ लाखों चित्र कैसे रैंक करें कन्वर्ट एक स्ट्रिंग (जैसे test123) जावा में बाइनरी में लिबोजपेग संकलित करना PHP: $ _SESSION के अंदर 'वस्तुओं' को संग्रहीत करना पायथन और क्लियर सीज़ सेट्यूव्यू "जबकि (* s ++ = * t ++)" स्ट्रिंग की प्रतिलिपि बनाते हैं? अजगर की मदद से फ़ाइल में सभी रिक्त पंक्तियों को कैसे हटाएं? Google Play सेवाओं 9.0.0 में अपग्रेड करने के बाद, डायनेमेटिक्स मॉड्यूल सी में एप्लिकेशन लटका हुआ है PHP के साथ ईमेल हैंडलिंग ईमेल पते की वैधता? एंड्रॉइड एसडीके मैनेजर रिपॉजिटरी चुनते समय "https://dl-ssl.google.com/android/repository/repository.xml यूआरएल लाने में असफल" त्रुटि देता है।

ऑटो और हमें क्या बताता है?

यदि आप कोड की तरह पढ़ते हैं

auto&& var = foo();

जहां foo किसी भी प्रकार T मूल्य द्वारा retuning फ़ंक्शन है फिर var T के प्रकार rvalue संदर्भ का एक lvalue है। लेकिन यह var लिए क्या मतलब है? क्या इसका मतलब है, हमें var के संसाधनों को चोरी करने की अनुमति है? क्या कोई उचित परिस्थितियां हैं जब आपको अपने कोड के पाठक को यह unique_ptr<> उपयोग करना चाहिए कि जब आप एक unique_ptr<> वापस unique_ptr<> हैं, तो बताएं कि आपके पास अनन्य स्वामित्व है? और T&& के उदाहरण के बारे में क्या है जब T कक्षा प्रकार का है?

मैं बस समझना चाहता हूं, यदि टेम्प्लेट प्रोग्रामिंग में उन लोगों की तुलना में auto&& किसी अन्य उपयोग के मामले हैं जैसे कि इस लेख में उदाहरणों में चर्चा की गई है, स्कॉट मेयेर द्वारा सार्वभौमिक संदर्भ ।

वेब के समाधान से एकत्रित समाधान "ऑटो और हमें क्या बताता है?"

auto&& var = <initializer> का प्रयोग करके आप कह रहे हैं: मैं किसी भी initializer को स्वीकार करेगा चाहे चाहे यह एक lvalue या rvalue अभिव्यक्ति है और मैं इसके constness को संरक्षित करेगा यह आमतौर पर अग्रेषण के लिए उपयोग किया जाता है (आमतौर पर T&& साथ) इसका कारण यह है कि एक "सार्वभौमिक संदर्भ", auto&& T&& या T&& , कुछ भी करने के लिए बाध्य होगा।

आप कह सकते हैं, ठीक है कि सिर्फ एक const auto& उपयोग क्यों न करें const auto& क्योंकि इससे कुछ भी बाँध होगा? एक const संदर्भ का प्रयोग करने में समस्या यह है कि यह const ! आप इसे बाद में किसी भी गैर-कॉन्फ्रेंस संदर्भ में बाँध नहीं कर पाएंगे या किसी भी सदस्य कार्यों को आमंत्रित नहीं करेंगे जिन्हें const चिह्नित नहीं किया गया है

एक उदाहरण के रूप में, कल्पना करें कि आप एक std::vector प्राप्त करना चाहते हैं, एक इरेरेटर को अपने पहले तत्व में लेना चाहते हैं और उस इरेरेटर द्वारा किसी तरह से इंगित किए गए मान को संशोधित करें:

 auto&& vec = some_expression_that_may_be_rvalue_or_lvalue; auto i = std::begin(vec); (*i)++; 

यह कोड प्रारंभिक अभिव्यक्ति की परवाह किए बिना ठीक ठीक संकलित करेगा auto&& विकल्प निम्नलिखित तरीकों से विफल होते हैं:

 auto => will copy the vector, but we wanted a reference auto& => will only bind to modifiable lvalues const auto& => will bind to anything but make it const, giving us const_iterator const auto&& => will bind only to rvalues 

इसलिए इसके लिए, auto&& पूरी तरह से काम करता है! इस तरह auto&& का उपयोग करने का एक उदाहरण लूप के for रेंज-आधारित है अधिक जानकारी के लिए मेरा दूसरा प्रश्न देखें

यदि आप इस तथ्य को संरक्षित करने के लिए अपने auto&& पर std::forward पर उपयोग करते हैं, तो यह मूल रूप से या तो एक लावलू या एक rvalue था, आपका कोड कहता है: अब जब मुझे आपकी ऑब्जेक्ट या तो एक लावल्यू या रैवल्यू एक्सप्रेशन से मिला है, तो मैं चाहता हूं जो भी मूल्यवानता मूल रूप से था इसलिए मैं इसे सबसे ज्यादा कुशलतापूर्वक उपयोग कर सकता हूं – यह इसे अमान्य कर सकता है जैसे की:

 auto&& var = some_expression_that_may_be_rvalue_or_lvalue; // var was initialized with either an lvalue or rvalue, but var itself // is an lvalue because named rvalues are lvalues use_it_elsewhere(std::forward<decltype(var)>(var)); 

इससे उपयोग की जाने वाली use_it_elsewhere को प्रदर्शन की खातिर (कॉपी से परहेज) करने के लिए अपनी हिम्मत चीर करने की अनुमति use_it_elsewhere है, जब मूल प्रारंभकर्ता एक use_it_elsewhere था।

इसका अर्थ क्या है कि हम क्या कर सकते हैं या जब हम var संसाधनों को चोरी कर सकते हैं? खैर, जब से auto&& किसी भी चीज से auto&& हो, हम संभवतया अपने स्वयं की चीजों को बाहर निकालने की कोशिश नहीं कर सकते – यह बहुत अच्छी तरह से एक लार्वेल या यहां तक ​​कि const भी हो सकता है हालांकि हम यह कर सकते हैं कि हम इसे अन्य कार्यों के लिए std::forward कर सकते हैं जो पूरी तरह से अपने अंदरूनी चीजों को नष्ट कर सकते हैं। जैसे ही हम ऐसा करते हैं, हमें var को अमान्य स्थिति में होना चाहिए।

अब आइए auto&& var = foo(); के मामले में इसे लागू करते हैं auto&& var = foo(); , जैसा कि आपके प्रश्न में दिया गया है, जहां foo मूल्य से एक T देता है इस मामले में हम यह सुनिश्चित करने के लिए जानते हैं कि प्रकार के var को T&& रूप में अनुमानित किया जाएगा। चूंकि हम निश्चित रूप से जानते हैं कि यह एक रैवल्यू है, हमें इसकी संसाधनों को चोरी करने के लिए std::forward की अनुमति की आवश्यकता नहीं है। इस विशिष्ट मामले में, यह जानने के लिए कि मूल्य के द्वारा foo रिटर्न , पाठक को इसे पढ़ना चाहिए: मैं फ़्यू से लौटा अस्थायी संदर्भ के लिए एक रैवल्यू संदर्भ ले रहा हूं, इसलिए मैं खुशी से उससे आगे बढ़ सकता हूं


एक परिशिष्ट के रूप में, मुझे लगता है कि जब कुछ some_expression_that_may_be_rvalue_or_lvalue एक्सप्रेशन_थैट_मैय_बी_आरवल्यू_ some_expression_that_may_be_rvalue_or_lvalue तरह अभिव्यक्ति हो सकती है, तो इसके बारे में उल्लेख करना some_expression_that_may_be_rvalue_or_lvalue होगा, "अच्छी तरह से आपका कोड बदल सकता है" स्थिति के अलावा तो यहां एक अनुचित उदाहरण है:

 std::vector<int> global_vec{1, 2, 3, 4}; template <typename T> T get_vector() { return global_vec; } template <typename T> void foo() { auto&& vec = get_vector<T>(); auto i = std::begin(vec); (*i)++; std::cout << vec[0] << std::endl; } 

यहां, get_vector<T>() यह सुंदर अभिव्यक्ति है जो सामान्य प्रकार T आधार पर या तो एक लावलू या रैवल्यू हो सकती है हम foo के टेम्प्लेट पैरामीटर के माध्यम से get_vector की वापसी प्रकार को get_vector

जब हम foo<std::vector<int>> , तो get_vector global_vec द्वारा global_vec , जो एक रैवल्यू अभिव्यक्ति देता है वैकल्पिक रूप से, जब हम foo<std::vector<int>&> कॉल करते हैं, तो global_vec संदर्भ से global_vec वापस करेगा, जिसके परिणामस्वरूप एक लावल्यू अभिव्यक्ति हो जाएगी।

यदि हम करें तो:

 foo<std::vector<int>>(); std::cout << global_vec[0] << std::endl; foo<std::vector<int>&>(); std::cout << global_vec[0] << std::endl; 

हमें निम्न आउटपुट मिलता है, जैसा कि अपेक्षित है:

 2 1 2 2 

अगर आप auto&& में किसी भी auto , auto& const auto& में कोड बदलते हैं, तो हमें वह परिणाम नहीं मिलेगा जो हम चाहते हैं।


आपके लॉन्च्यु या रैवल्यू एक्सप्रेशन के साथ आपका auto&& रेफरेंस शुरू किया गया है या नहीं, इस पर आधारित प्रोग्राम लॉजिक बदलने का एक वैकल्पिक तरीका है टाइप लक्षण:

 if (std::is_lvalue_reference<decltype(var)>::value) { // var was initialised with an lvalue expression } else if (std::is_rvalue_reference<decltype(var)>::value) { // var was initialised with an rvalue expression } 

सबसे पहले, मैं इस उत्तर को पढ़ने के लिए सुझाव देता हूं कि साइड-बाय-स्टेपमेंट के लिए साइड-पठन के रूप में कैसे सार्वभौमिक संदर्भों के लिए टेम्पलेट आर्ग्यूमेंट कटौती काम करता है।

क्या इसका मतलब है, हमें var के संसाधनों को चोरी करने की अनुमति है?

जरुरी नहीं। क्या होगा अगर foo() ने अचानक एक संदर्भ वापस किया, या आपने कॉल को बदल दिया लेकिन var के उपयोग को अपडेट करने में भूल गए? या यदि आप जेनेरिक कोड में हैं और वापसी के प्रकार foo() आपके पैरामीटर के आधार पर बदल सकते हैं?

auto&& template<class T> void f(T&& v); बारे में सोचें कि template<class T> void f(T&& v); में T&& के समान बिल्कुल वैसा ही हो template<class T> void f(T&& v); , क्योंकि यह (लगभग ) वास्तव में है आप कार्यों में सार्वभौमिक संदर्भों के साथ क्या करते हैं, जब आपको उन्हें पास करना पड़ता है या उन्हें किसी भी तरह से उपयोग करना है? आप मूल मूल्य श्रेणी वापस पाने के लिए std::forward<T>(v) का उपयोग करते हैं। यदि यह आपके फ़ंक्शन में पारित होने से पहले एक लार्वेल है, तो यह std::forward माध्यम से पारित होने के बाद एक लावलू रहता है। अगर यह एक रवैया था, तो यह फिर से एक रैवल्यू बन जाएगी (याद रखें, एक नामांकित रैवल्यू संदर्भ एक लावलू है)।

तो, आप कैसे एक सामान्य फैशन में var उपयोग करते हैं? std::forward<decltype(var)>(var) उपयोग करें यह फ़ंक्शन टेम्पलेट के ऊपर std::forward<T>(v) के समान बिल्कुल काम करेगा। यदि var एक T&& T& , तो आपको एक रैवल्यू वापस मिल जाएगी, और यदि यह T& , तो आपको एक लावल्यू वापस मिल जाएगा

तो, विषय पर वापस: auto&& v = f(); क्या करें auto&& v = f(); और std::forward<decltype(v)>(v) एक कोडबेस में हमें बताओ? वे हमें बताते हैं कि v को अधिग्रहित और सबसे प्रभावी तरीके से पारित किया जाएगा। याद रखें, हालांकि, इस तरह के एक वैरिएबल को अग्रेषित करने के बाद, यह संभव है कि इसे ले जाया गया है, इसलिए इसे इसे रीसेट किए बिना इसका और उपयोग करना गलत होगा।

व्यक्तिगत रूप से, जब मैं संशोधनीय चर की आवश्यकता होती है, तो मैं जेनेरिक कोड में auto&& एंड ए का उपयोग करता हूं I सही-फ़ॉरवर्डिंग एक रैवल्यू बदल रहा है, क्योंकि चालन प्रक्रिया संभावित रूप से अपनी हिम्मत चुरा लेती है। अगर मैं बस आलसी होना चाहता हूँ (यानी, मैं इसे जानता हूं, तो भी उस प्रकार का नाम नहीं लिखता) और उसे संशोधित करने की आवश्यकता नहीं है (जैसे, जब किसी श्रेणी के केवल छपाई तत्व), तो मैं auto const&


auto अब तक अलग है कि auto v = {1,2,3}; v एक std::initializer_list बना देगा, जबकि f({1,2,3}) एक कटौती विफलता होगी।

कुछ प्रकार T पर विचार करें, जिसमें चालन निर्माता है, और मान लें

 T t( foo() ); 

उस चालन निर्माता का उपयोग करता है

अब, foo से वापसी को पकड़ने के लिए एक मध्यवर्ती संदर्भ का उपयोग करें:

 auto const &ref = foo(); 

यह चालन निर्माता के उपयोग से बाहर निकलने का नियम है, इसलिए बदले गए मूल्य को स्थानांतरित करने के बजाय प्रतिलिपि करना होगा (यहां तक ​​कि यदि हम यहां std::move उपयोग करते हैं, तो हम वास्तव में एक कॉन्स्ट रेफरी में नहीं जा सकते हैं)

 T t(std::move(ref)); // invokes T::T(T const&) 

हालांकि, अगर हम उपयोग करते हैं

 auto &&rvref = foo(); // ... T t(std::move(rvref)); // invokes T::T(T &&) 

चालन निर्माता अभी भी उपलब्ध है


और अपने अन्य प्रश्नों को संबोधित करने के लिए:

… क्या कोई उचित परिस्थितियां हैं जब आपको अपने कोड के पाठक को कुछ कहने के लिए ऑटो एंड एंड का उपयोग करना चाहिए …

पहली चीज, जैसा कि ज़ीओ कहते हैं, अनिवार्य रूप से मैं एक्स को यथासंभव कुशलता से पारित कर रहा हूं , जो कुछ भी एक्स है I इसलिए, जो कोड को देख रहा है जो auto&& आंतरिक रूप से उपयोग करता है, उसे यह सूचित करना चाहिए कि वह आंतरिक रूप से स्थानांतरित शब्दों का उपयोग करेगा जहां उपयुक्त हो।

… जैसे आप जब आप एक अद्वितीय_प्रतिकार <> वापस लौटते हैं, तो बताएं कि आपके पास अनन्य स्वामित्व है …

जब कोई फ़ंक्शन टेम्पलेट प्रकार T&& का तर्क लेता है, तो यह कह रहा है कि वह उस ऑब्जेक्ट को स्थानांतरित कर सकता है जिसमें आप पास करते हैं। unique_ptr रिटर्निंग स्पष्ट रूप से कॉलर को स्वामित्व देता है; स्वीकार करने वाला T&& कॉलर से स्वामित्व को निकाल सकता है (यदि कोई चालन ctor मौजूद है, आदि)।

auto && सिंटैक्स सी ++ 11 की दो नई सुविधाओं का उपयोग करता है:

  1. auto अंग से कंपाइलर संदर्भ के आधार पर प्रकार को निकाल देता है (इस मामले में वापसी मूल्य)। यह किसी भी संदर्भ योग्यता के बिना है (आप निर्दिष्ट करने के लिए कि क्या आप T , T & या T && T & चाहते हैं, T & लिए एक निर्धारित प्रकार T )।

  2. && नई चाल शब्दों है एक प्रकार का समर्थन T(T && other) एक निर्माता T(T && other)T(T && other) लागू करता है जो सामग्री को बेहतर ढंग से नए प्रकार में ले जाते हैं। यह किसी ऑब्जेक्ट को एक गहरी प्रतिलिपि बनाने के बजाय आंतरिक प्रतिनिधित्व को स्वैप करने देता है।

यह आपको ऐसा कुछ करने की अनुमति देता है:

 std::vector<std::string> foo(); 

इसलिए:

 auto var = foo(); 

वापस सदिश (महंगी) की एक प्रति करेंगे, लेकिन:

 auto &&var = foo(); 

वेक्टर के आंतरिक प्रतिनिधित्व को स्वैप करेगा ( foo से वेक्टर और foo से खाली वेक्टर), तो तेज़ हो जाएगा

इसका उपयोग नए लूप सिंटैक्स में किया जाता है:

 for (auto &item : foo()) std::cout << item << std::endl; 

जहां for-loop को foo से रिटर्न मान पर auto && और एंड होल्ड है और item foo में प्रत्येक मान का एक संदर्भ है।