2016-10-21 7 views
5

एक लैम्ब्डा को देखते हुए? मानक में यह कहां है?क्यों लैम्ब्डा सीवी और रेफरी हटा देता है?</p> <pre><code>auto f = [](const T& var){ return var; }; </code></pre> <p>क्यों <code>f</code> की वापसी प्रकार <code>T</code> (नहीं <code>const T&</code>) है:

+2

ध्यान दें कि आप '[] (कॉन्स टी एंड var) -> कॉन्स्ट ऑटो और' 'कॉन्स और' रिटर्न प्रकार प्राप्त करने के लिए उपयोग कर सकते हैं। – Simple

+2

लैम्बडा का रिटर्न प्रकार अन्यथा निर्दिष्ट होने तक 'ऑटो' है। सामान्य 'ऑटो' कटौती नियम लागू होते हैं। –

उत्तर

5

बिंदु है:

  1. वापसी प्रकार कटौती काम टेम्पलेट प्रकार कटौती शासन के लिए स्वत: का उपयोग।
  2. रिटर्न प्रकार पास-बाय-वैल्यू के रूप में डेल किया गया है; जिसका अर्थ है कि कटौती के लिए उपयोग की जाने वाली अभिव्यक्ति के संदर्भ-स्तर और शीर्ष-स्तर के सीवी-क्वालीफायर (यानी var) को अनदेखा किया जाता है। मानक से

उद्धरण:

बारे auto:

प्लेसहोल्डर ऑटो प्रकार-विनिर्देशक, deduced प्रकार टी 'की जगह टी टेम्पलेट तर्क कटौती के लिए नियमों का उपयोग कर निर्धारित किया जाता है है । एक नए आविष्कार प्रकार टेम्पलेट पैरामीटर यू के साथ ऑटो की घटनाओं को प्रतिस्थापित करके टी से टी प्राप्त करें या, अगर प्रारंभिक प्रतिलिपि = प्रारंभकर्ता_सूची के साथ प्रारंभिक प्रतिलिपि-प्रारंभिक है। फ़ंक्शन कॉल ([temp.deduct.call]) से टेम्पलेट तर्क कटौती के नियमों का उपयोग करके यू के लिए एक मान घटाएं, जहां पी एक फ़ंक्शन टेम्पलेट पैरामीटर प्रकार है और संबंधित तर्क ई है। यदि कटौती विफल हो जाती है, तो घोषणा खराब हो जाती है। अन्यथा, टी 'पी

में deduced यू प्रतिस्थापन template argument deduction from a function call के शासन के बारे में प्राप्त किया जाता है:

तो पी एक संदर्भ प्रकार नहीं है:

  • तो एक एक है सीवी-योग्य प्रकार, प्रकार के कटौती के लिए ए के प्रकार के शीर्ष-स्तर के सीवी-क्वालीफायर को अनदेखा किया जाता है।

बारे reference:

एक अभिव्यक्ति शुरू में "टी के संदर्भ में" प्रकार है ([dcl.ref], [dcl.init.ref]), प्रकार के लिए निकाला जाता किसी और विश्लेषण से पहले टी।

तो var (अर्थात A), const T& है निष्कर्ष निकाला वापसी प्रकार T यहाँ होगा।

4

यह सी ++ के बारे में एक और अधिक मौलिक मुद्दा है। विशेष रूप से लैम्ब्डा या auto के साथ कुछ भी नहीं करना है।

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

int x = 3; 
int &y = x; 

वास्तव में, यह (decltype के माध्यम से छोड़कर) उन्हें अलग करने के लिए असंभव है: निम्न कोड में, वहाँ x और y बीच कोई वास्तविक अंतर है। int प्रकार के दोनों प्रकार हैं। आप foo(x) और foo(y) कॉल करते हैं, संकलक उन दोनों को एक ही प्रकार के और मूल्य वर्ग के होने और इसलिए एक ही अधिभार चयन किया जाता है के रूप में व्यवहार करेगा।

मैं कह रही है कि उन दोनों को एक ही वस्तु के लिए संदर्भ द्वारा x और y व्याख्या करेंगे। वे एक ही वस्तु के लिए दो अलग-अलग 'नाम' हैं।

इसलिए return x और return y एक-दूसरे के बराबर हैं, और इसलिए लैम्बडा को इसके रिटर्न प्रकार को कम करते समय & पर ध्यान नहीं दिया जाएगा।

यही कारण है & नजरअंदाज कर दिया है। सी ++ के रूप में ज्यादा संभव के रूप में & "अनदेखा" की कोशिश करता है, ठीक क्रम कि संदर्भ मूल वस्तु के रूप में पूरी तरह से बराबर इलाज किया जा सकता है।

अब यह स्थापित किया गया है कि हम मूल्य से वापस आ रहे हैं, संदर्भ के अनुसार नहीं, तो हम समझ सकते हैं कि const को भी क्यों नजरअंदाज कर दिया गया है। किसी ऑब्जेक्ट की एक प्रति const होने की आवश्यकता नहीं है। उलटा भी में इस पर विचार करें: हम एक समारोह के int पैरामीटर के रूप में एक const int तर्क पारित कर सकते हैं। कोई अनुगामी वापसी के साथ auto वापसी कार्यों का

+0

सावधान ... "संदर्भ वस्तु" जैसी कोई चीज़ नहीं है; एक संदर्भ एक वस्तु नहीं है। साथ ही, 'foo' पर दोनों कॉल आपके उदाहरण में संदिग्ध होंगे। और, जबकि ''' को छोड़ने के लिए उत्तर को गैर-भाषा-वकील तर्क के रूप में देखा जा सकता है, यह स्पष्ट नहीं करता कि क्यों' const' गिरा दिया गया है। – bogdan

+1

धन्यवाद @bogdan, मुझे अपने अधिभार सेट का परीक्षण करना चाहिए था। मैंने कुछ बदलाव किए हैं। मुझे लगता है कि यह अभी भी एक आदर्श उत्तर नहीं है, लेकिन मुझे लगता है कि यह जोर देना उपयोगी है कि यह डिज़ाइन केवल कुछ ऐसा नहीं है जो 2011 में "पतली हवा से" सी ++ 11 में लिखा गया था, और यह इसके बजाय एक सतत डिजाइन का प्रतिनिधित्व करता है पूरे सी ++ में संदर्भों को आम तौर पर संदर्भित वस्तु के समान व्यवहार करना चाहिए (जिसमें एक ही प्रकार और मूल्य श्रेणी शामिल है)। –

2

वापसी प्रकार कटौती में टाइप सी ++ में 11 या 14 से किया जाता है जैसे कि आप

auto retval = /* return expression */ 

और autoहमेशा एक मान प्रकार deduces किया था।

lambdas सी ++ 11 में केवल auto वापसी कार्य हैं। सी ++ 14 में इसे अन्य कार्यों (समान नियमों के बाद) तक बढ़ा दिया गया था।

C++ 11 यदि आप अपने लैम्ब्डा पर एक ->decltype(var) या एक ->int const& अनुगामी वापसी प्रकार के साथ इसे ठीक कर सकते हैं।

C++ में 14 तो आप बस ->decltype(auto), जो

auto retval = /* return expression */ 

से वापसी प्रकार कटौती नियमों में परिवर्तन कर सकते हैं

decltype(/* return expression */) retval = /* return expression */ 

अधिक की तरह है, जो अपने मामले में, गिर नहीं करने का मतलब है होना करने के लिए & या const

ध्यान दें कि const& पैरामीटर लौटने पर बहुत खतरनाक है, क्योंकि रावल को const& में निहित किया जा सकता है, और संदर्भ जीवनकाल एक्सटेंशन फ़ंक्शन कॉल के पीछे नहीं आता है।तो:

auto&& x = f(some_function()); 
// or 
int const& x = f(some_function()); 

उत्पन्न x अस्थायी some_function() द्वारा वापस करने के लिए एक झूलने संदर्भ:

auto&& x = some_function(); 
// or 
int const& x = some_function(); 

सुरक्षित भले ही some_function() एक अस्थायी देता है, जबकि यह सोचते हैं f तरह से बर्ताव करता है आप f व्यवहार करने के लिए चाहते हैं।

यह आश्चर्यजनक रूप से चीजों को तोड़ सकता है, इस तथ्य की तरह कि for(:) लूप दृश्य के पीछे auto&& पैरामीटर का उपयोग करते हैं, और रेंज अभिव्यक्ति के प्रारंभिकरण और पुनरावृत्ति के निष्पादन के बीच अस्थायी को साफ करते हैं।

यह उत्तर अभी तक पूरा नहीं हुआ है, क्योंकि मैंने मानक में संदर्भ नहीं जोड़े हैं।

संबंधित मुद्दे