2012-04-23 2 views
12

मैंने सही अग्रेषण के बारे में जानने के लिए एक परीक्षण केस स्थापित किया।सी ++ 11: std :: आगे की subtlety: पहचान वास्तव में आवश्यक है?

std::string inner(const std::string& str) { 
return "const std::string&"; 
} 
std::string inner(std::string& str) { 
    return "std::string&"; 
} 
std::string inner(const std::string&& str) { 
    return "const std::string&&"; 
} 
std::string inner(std::string&& str) { 
    return "std::string&&"; 
} 

template <typename T> void outer(T&& t) { 
    std::cout << "t: " << t << std::endl; 
    std::cout << "perfect forward: " << inner(std::forward<T>(t)) << std::endl; 
    std::cout << std::endl; 
} 

void PerfectForwarding() 
{ 
    outer("literal"); 
    outer(lvalue); 
    outer(constlvalue); 
    outer(rvalue()); 
    outer(constrvalue()); 
} 

std::forward अपेक्षा के अनुसार काम करता है। दिलचस्प व्यवहार उभर जब मैं पहचान के बिना अपने खुद के आगे समारोह को लागू:

template <typename T> T&& MyForward(T& t) 
{ 
    return ((T&&)t); 
} 

बाहरी में MyForward साथ std::forward जगह ठीक उसी परिणाम देता है! व्यवहार सवाल पूछता है कि पहचान का उपयोग क्यों किया जाता है?

संकलक VS2010

अद्यतन 1: प्रकार कटौती को रोकने

AFAIK के संदर्भ में, विशेष प्रकार कटौती नियम केवल टी & & पर सक्रिय है। आगे की परिभाषा पर ध्यान दें, forward(typename identity<T>::type& t)। तर्क प्रकार में केवल एक & है। असल में, मैंने पहचान का उपयोग करने के लिए माईफोर्ड को बदलने के बाद, (टी & &) कास्टिंग छोड़ दिया, उदाहरण संकलित नहीं होता है। सतह पर, लालू से रावल्यू तक कास्टिंग आगे काम करने लगता है।

अद्यतन 2: जीसीसी 4.5, वही व्यवहार के साथ ideone.com पर परीक्षण किया गया।

+1

"पहचान" से आपका क्या मतलब है? 'Std :: forward' या' remove_reference :: type' के दो ओवरलोड्स? – kennytm

+1

पहचान पहचान संरचना, आगे की तर्क के प्रकार को संदर्भित करती है: _Ty && आगे (टाइपनाम पहचान <_Ty> :: प्रकार और _Arg) –

+2

यह कुछ पूर्व-मानक हस्ताक्षर होना चाहिए। मानक एक 'T && आगे है (typename remove_reference :: प्रकार और टी)' (और अधिभार लेना '&&')। – kennytm

उत्तर

13

remove_reference<T> (identity मसौदा के एक पुराने संस्करण में था, लेकिन remove_reference में बदल गया था) प्रकार कटौती को रोकने के लिए प्रयोग किया जाता है: std::forwardकेवल एक स्पष्ट प्रकार पैरामीटर के साथ काम करता है। अन्यथा निम्नलिखित संकलित होंगे:

std::forward(t) 

... लेकिन यह सही काम नहीं करेगा।

इस मुद्दे के बारे में lvalues ​​/ rvalues ​​के साथ, कृपया ध्यान दें कि two overloads of std::forward हैं: एक के लिए एक, लालसा के लिए, दूसरा रावल के लिए।

वास्तव में, MyForward कार्यान्वयन std::move जैसा है: यह अंतराल में रावजू में बदल जाता है (अंतर यह है कि चाल भी रावलों को स्वीकार करती है)।

+0

कृपया अपडेट देखें। –

+0

इस वीएस -2010 में केवल एक ही है। और यह एक के साथ काम करता है। तो हमें दो की आवश्यकता क्यों है? –

+0

@ कैंडीसिउ यह वीएस -2010 पर काम करता है क्योंकि मानक को अंतिम रूप देने से पहले इसे भेज दिया गया था। VS2010 भेजे गए समय के बीच नियम बदल गए हैं और मानक प्रकाशित किया गया था। हमें दो की जरूरत है क्योंकि अंतराल '&&' से बंधे नहीं होंगे, और राजस्व 'और' से बंधे नहीं होंगे। –

0

मैं वी.एस. 2010 अपने MyForward और उनके forward के बीच फर्क सिर्फ इतना में forward और identity की परिभाषा की जाँच की है कि आप एक T& पैरामीटर का उपयोग और वे एक typename identity<T>::type& पैरामीटर का उपयोग है। और identity<T>::type सिर्फ T है।

इस अंतर का सबसे महत्वपूर्ण (शायद एकमात्र) प्रभाव यह है कि उनके forward का उपयोग करने के लिए टेम्पलेट तर्क स्पष्ट रूप से निर्दिष्ट किया जाना चाहिए जबकि आपके MyForward के टेम्पलेट तर्क को कॉल से लिया जा सकता है।

+0

"घटाया जा सकता है" ... अच्छा, यह गलत तरीके से –

+0

को घटाया जाएगा, यदि पास हो बाहरी (टी एंड ए) के लिए एक लालसा, टी को एक रावल्यू संदर्भ प्रकार में डाला जाएगा। – Cosyn

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