दिलचस्प पोस्ट
हम इनपुट को पढ़ने के बाद cin.clear () और cin.ignore () क्यों कॉल करेंगे? सी # में "उपयोग" का उपयोग जावा में स्विंग जीयूआई के लिए पृष्ठभूमि के रूप में एक छवि कैसे सेट करें? आप कैसे सी # में कोड के साथ नेटवर्क सेटिंग्स (आईपी पता, डीएनएस, WINS, होस्ट नाम) बदल सकते हैं विंडोज़ के नीचे गिट: एमएसवायएस या साइगविन? setValue: forUndefinedKey: यह वर्ग कुंजी के लिए मूल्य मान कोडन-अनुरूप नहीं है हमारे युद्ध / वेब-आईएनएफ फ़ोल्डर में संसाधन के लिए फ़ाइल पथ? बीओएम के साथ यूटीएफ -8 फाइलों की तलाश करने का शानदार तरीका? jquery चेक एक बटन के साथ सभी चेकबॉक्स को अनचेक करें कैसे दृश्य स्टूडियो 2013 में सी # 6.0 सुविधा को सक्षम करने के लिए? क्या मैं JSON को पायथन में एक ऑर्डर किए गए आदेश में लोड कर सकता हूं? एक "हैलो वर्ल्ड" वेबसॉकेट उदाहरण बनाना क्यों नहीं "अगर कुछ नहीं:" अगर "कुछोबज == कोई भी नहीं": "पायथन में" MySQL: @ वैरिएबल बनाम चर क्या फर्क पड़ता है? क्या स्थानीय चर की स्मृति को इसके दायरे के बाहर पहुंचाया जा सकता है?

STD :: आगे कैसे काम करता है?

संभव डुप्लिकेट:
आगे का उपयोग करने के फायदे

मुझे पता है कि यह क्या करता है और इसका उपयोग कब किया जाता है लेकिन मैं अभी भी अपने सिर को लपेट नहीं कर सकता कि यह कैसे काम करता है। कृपया यथासंभव विस्तृत बताएं और बताएं कि क्या std::forward गलत होगा यदि उसे टेम्पलेट आर्ग्यूमेंट कटौती का उपयोग करने की अनुमति दी गई थी।

मेरे भ्रम का एक हिस्सा यह है: "यदि उसका नाम है, तो यह एक लावलु है" – अगर ऐसा होता है तो मैं std::forward अलग तरह से व्यवहार क्यों करता हूं जब मैं thing& x पास करता हूं?

वेब के समाधान से एकत्रित समाधान "STD :: आगे कैसे काम करता है?"

सबसे पहले, हम std::forward कि मानक के अनुसार कौन सी मानक std::forward करता है:

§20.2.3 [forward] p2

रिटर्न: static_cast<T&&>(t)

(जहां T स्पष्ट रूप से निर्दिष्ट टेम्पलेट पैरामीटर है और t पारित तर्क है।)

अब संदर्भ ढहने के नियम याद रखें:

 TR R T& & -> T& // lvalue reference to cv TR -> lvalue reference to T T& && -> T& // rvalue reference to cv TR -> TR (lvalue reference to T) T&& & -> T& // lvalue reference to cv TR -> lvalue reference to T T&& && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T) 

( इस उत्तर से बेईमानी से चोरी हो गई।)

और फिर चलो एक क्लास पर एक नज़र डालें जो सही फ़ॉरवर्डिंग को काम करना चाहता है:

 template<class T> struct some_struct{ T _v; template<class U> some_struct(U&& v) : _v(static_cast<U&&>(v)) {} // perfect forwarding here // std::forward is just syntactic sugar for this }; 

और अब एक उदाहरण का आह्वान:

 int main(){ some_struct<int> s1(5); // in ctor: '5' is rvalue (int&&), so 'U' is deduced as 'int', giving 'int&&' // ctor after deduction: 'some_struct(int&& v)' ('U' == 'int') // with rvalue reference 'v' bound to rvalue '5' // now we 'static_cast' 'v' to 'U&&', giving 'static_cast<int&&>(v)' // this just turns 'v' back into an rvalue // (named rvalue references, 'v' in this case, are lvalues) // huzzah, we forwarded an rvalue to the constructor of '_v'! // attention, real magic happens here int i = 5; some_struct<int> s2(i); // in ctor: 'i' is an lvalue ('int&'), so 'U' is deduced as 'int&', giving 'int& &&' // applying the reference collapsing rules yields 'int&' (& + && -> &) // ctor after deduction and collapsing: 'some_struct(int& v)' ('U' == 'int&') // with lvalue reference 'v' bound to lvalue 'i' // now we 'static_cast' 'v' to 'U&&', giving 'static_cast<int& &&>(v)' // after collapsing rules: 'static_cast<int&>(v)' // this is a no-op, 'v' is already 'int&' // huzzah, we forwarded an lvalue to the constructor of '_v'! } 

मुझे उम्मीद है कि यह चरण-दर-चरण उत्तर आपको और दूसरों को समझने में मदद करता है कि कैसे std::forward काम करता है

मुझे लगता है कि std::forward रूप में static_cast<T&&> की व्याख्या भ्रमित है। एक कलाकार के लिए हमारा अंतर्ज्ञान यह है कि वह एक प्रकार को किसी अन्य प्रकार में परिवर्तित कर देता है – इस मामले में यह एक रैवल्यू संदर्भ के लिए एक रूपांतरण होगा। यह! इसलिए हम एक रहस्यमय चीज का इस्तेमाल करते हुए एक रहस्यमय चीज़ को समझा रहे हैं। इस विशेष कलाकार को क्सीओ के उत्तर में एक मेज से परिभाषित किया गया है। लेकिन सवाल है: क्यों? तो मेरी समझ है:

मान लीजिए मैं आपको एक std::vector<T> v पास करना चाहता हूं std::vector<T> v जिसे आप अपने डेटा संरचना में डेटा सदस्य के रूप में स्टोर करना चाहते हैं _v । सहज (और सुरक्षित) समाधान हमेशा अपने अंतिम गंतव्य में वेक्टर की प्रतिलिपि बनाना होगा। इसलिए यदि आप ऐसा कर रहे हैं तो मध्यस्थ फ़ंक्शन (विधि), उस फ़ंक्शन को संदर्भ लेने के रूप में घोषित किया जाना चाहिए। (यदि आप इसे वैक्टर से एक वेक्टर लेने के रूप में घोषित करते हैं, तो आप एक अतिरिक्त पूरी तरह से अनावश्यक प्रतिलिपि का प्रदर्शन करेंगे।)

 void set(std::vector<T> & v) { _v = v; } 

यह सब ठीक है अगर आपके पास आपके हाथ में एक लावलु है, लेकिन क्या एक रैवल्यूए के बारे में है? मान लीजिए कि सदिश एक समारोह makeAndFillVector() फोन करने का परिणाम है। यदि आप प्रत्यक्ष असाइनमेंट करते हैं:

 _v = makeAndFillVector(); 

संकलक इसे प्रतिलिपि बनाने के बजाय वेक्टर को स्थानांतरित करेगा। लेकिन अगर आप एक मध्यस्थ को set() , तो set() , आपकी तर्क की रैवल्यू प्रकृति के बारे में जानकारी खो जाएगी और एक प्रतिलिपि बनाई जाएगी।

 set(makeAndFillVector()); // set will still make a copy 

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

आम तौर पर आप इसे फ़ंक्शन set() ओवरलोडिंग set() अलग करके लावलुओं और रैवल्यूज़ के लिए करेंगे:

 set(std::vector<T> & lv) { _v = v; } set(std::vector<T> && rv) { _v = std::move(rv); } 

लेकिन अब कल्पना कीजिए कि आप एक टेम्प्लेट फ़ंक्शन लिख रहे हैं जो T साथ set() कॉल set() इस तथ्य के बारे में चिंता न करें कि हमारे set() केवल वैक्टर के लिए निर्धारित हैं)। चाल यह है कि आप इस टेम्पलेट को set() के पहले संस्करण को कॉल करना चाहते हैं, जब टेम्प्लेट फ़ंक्शन एक लावल्यू के साथ तत्काल होता है, और दूसरा जब यह एक आरवल्यु के साथ आरंभ होता है

सबसे पहले, इस समारोह के हस्ताक्षर को क्या होना चाहिए? इसका उत्तर है:

 template<class T> void perfectSet(T && t); 

आप इस टेम्पलेट फ़ंक्शन को कैसे कॉल करते हैं इस पर निर्भर करते हुए, टाइप T को अलग-अलग ढंग से अलग ढंग से अनुमानित किया जाएगा। यदि आप इसे लार्वेल के साथ कहते हैं:

 std::vector<T> v; perfectSet(v); 

वेक्टर v संदर्भ से पारित किया जाएगा। लेकिन अगर आप इसे रैवल्यू के साथ कहते हैं:

 perfectSet(makeAndFillVector()); 

(अनाम) वेक्टर रैवल्यू संदर्भ से पारित किया जाएगा तो सी +11 11 जादू उद्देश्यपूर्वक इस तरह स्थापित किया जाता है कि यदि संभव हो तो तर्कों के rvalue प्रकृति को संरक्षित करें।

अब, आदर्श के अंदर, आप पूरी तरह से set() के सही अधिभार के तर्क को पारित करना चाहते हैं। यह वह जगह है जहां std::forward आवश्यक है:

 template<class T> void perfectSet(T && t) { set(std::forward<T>(t)); } 

Std :: forward बिना संकलक को यह मानना ​​होगा कि हम संदर्भ से टी पास करना चाहते हैं। अपने आप को समझाने के लिए कि यह सच है, इस कोड की तुलना करें:

 void perfectSet(T && t) { set(t); set(t); // t still unchanged } 

इसके लिए:

 void perfectSet(T && t) { set(std::forward<T>(t)); set(t); // t is now empty } 

यदि आप स्पष्ट रूप से अग्रेषित नहीं करते हैं, तो संकलक को संरक्षित रूप से यह मानना ​​है कि आप पुनः प्रवेश कर सकते हैं और सेट के lvalue संदर्भ संस्करण को चुना है। लेकिन अगर आप आगे बढ़ते t , तो कंपाइलर इसकी रवैइव-रास को संरक्षित करेगा और set() के रैवल्यू संदर्भ संस्करण को बुलाया जाएगा। यह संस्करण t की सामग्री को स्थानांतरित करता t , जिसका अर्थ है कि मूल खाली हो जाता है।

यह उत्तर मुझे शुरू में मान लिया गया था 😉

यह काम करता है क्योंकि जब सही फ़ॉरवर्डिंग लागू किया जाता है, तो टाइप टी मूल्य प्रकार नहीं है, यह एक संदर्भ प्रकार भी हो सकता है।

उदाहरण के लिए:

 template<typename T> void f(T&&); int main() { std::string s; f(s); // T is std::string& const std::string s2; f(s2); // T is a const std::string& } 

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

जब आप किसी नामांकित रैवल्यू संदर्भ को संदर्भित करते हैं , तो यह वास्तव में एक लावलु है हालांकि, इसके बाद के माध्यम से इसका पता लगाया जाता है कि यह वास्तव में एक रैवल्यू है, और सही ढंग से एक रिव्यू देता है जिसे अग्रेषित किया जाना है।