2013-06-08 19 views
24

मैंstd :: remove_reference समझाया गया?

template< class T > struct remove_reference  {typedef T type;}; 
template< class T > struct remove_reference<T&> {typedef T type;}; 
template< class T > struct remove_reference<T&&> {typedef T type;}; 

नीचे के रूप में std::remove_reference के लिए संभव कार्यान्वयन देखा ऐसा क्यों है वहाँ lvalue और rvalue reference के लिए विशेषज्ञताओं हैं कि है? सामान्य टेम्पलेट स्वयं पर्याप्त नहीं होगा और संदर्भ को हटा देगा? मैं यहां उलझन में हूं क्योंकि T& या T&& विशेषज्ञता में अगर मैं ::type का उपयोग करने का प्रयास करता हूं तो मुझे अभी भी T& या T&& प्राप्त करना चाहिए?

क्या आप समझा सकते हैं कि, हम remove_reference<t>::type&& पर क्यों गए? (क्या ऐसा इसलिए है क्योंकि पैरामीटर का नाम दिया गया है, इसलिए इसे चाल समारोह के अंदर एक लाभा के रूप में माना जाएगा?)।

क्या आप यह भी बता सकते हैं कि मैं किस प्रकार से पता लगा सकता हूं और प्रिंट कर सकता हूं? उदाहरण के लिए अगर अपने प्रकार int के rvalue तो मैं बाहर मुद्रित करने के लिए है कि int&& पारित किया गया था सक्षम होना चाहिए? (मैं जाँच करने के लिए std::is_same उपयोग कर रहे हैं, लेकिन मैन्युअल रूप से।)

अपने समय के लिए धन्यवाद।

+0

का उपयोग यह एक ** बहुत ** अच्छा सवाल है! – gedamial

उत्तर

34

यह क्यों है कि लैवल्यू और रावल्यू संदर्भ के लिए विशेषज्ञताएं हैं?

अगर केवल प्राथमिक टेम्पलेट से ही अस्तित्व में है, तो कर रही है:

remove_reference<int&>::type 

आप दे सकते हैं:

int& 

और कर:

remove_reference<int&&>::type 

आप दे सकते हैं:

int&& 

जो आप नहीं चाहते हैं। लाल्व संदर्भ और रावल्यू संदर्भों के लिए विशेषज्ञता क्रमशः आपके द्वारा पारित तर्क तर्क से & और && को अलग करने की अनुमति देती है।

उदाहरण के लिए, यदि आप कर रहे हैं:

remove_reference<int&&> 

प्रकार int&&T जा रहा है int साथ, पैटर्न T&& विशेषज्ञता द्वारा निर्दिष्ट से मेल खाएगी। के बाद से विशेषज्ञता प्रकार उर्फ ​​type को परिभाषित करता है T (इस मामले, int में) हो सकता है, कर रही है:

remove_reference<int&&>::type 

आप int देंगे।

आप कैसे, हम क्यों move में remove_reference<t>::type&& लिए डाली समझा सकता है?

क्योंकि अगर move() इस प्रकार परिभाषित किया गया है कि:

template<typename T> 
    T&& move(T&& t) { ... } 
// ^^^ 
// Resolves to X& if T is X& (which is the case if the input has type X 
// and is an lvalue) 

फिर वापसी प्रकार X& हो सकता है अगर move() का तर्क प्रकार X (कि कैसे तथाकथित "सार्वभौमिक संदर्भ" है की एक lvalue है)। हम यह सुनिश्चित करना चाहते हैं कि वापसी का प्रकार हमेशा एक रावल्यू संदर्भ है।

move() का उद्देश्य आपको वापस एक rvalue, कोई बात नहीं क्या आप इनपुट में पारित दे रहा है। चूंकि फ़ंक्शन के लिए फ़ंक्शन कॉल होता है जिसके रिटर्न प्रकार एक रावल्यू संदर्भ एक रावल्यू है, हम वास्तव में move() चाहते हैं कि हमेशा एक रावल्यू संदर्भ लौटाएं। क्योंकि एक गैर संदर्भ प्रकार के && जोड़कर हमेशा एक rvalue संदर्भ प्रकार की उपज के लिए गारंटी है

, इसलिए हम remove_reference<T>::type&& है।

क्या आप यह भी बता सकते हैं कि मैं किस प्रकार से पता लगा सकता हूं और प्रिंट कर सकता हूं?

मुझे यकीन है कि क्या आप "प्रिंट" से यहाँ मतलब यह नहीं कर रहा हूँ। कोई पोर्टेबल तरीका नहीं है जिसे मैं किसी प्रकार के नाम को स्ट्रिंग में परिवर्तित करने के बारे में जानता हूं (इससे कोई फर्क नहीं पड़ता कि आप उस प्रकार को कैसे प्राप्त करते हैं)।

अपने लक्ष्य को यकीन है कि एक rvalue पारित किया गया था बनाने के लिए है, तो दूसरी ओर, आप एक स्थिर दावे तो तरह इस्तेमाल कर सकते हैं:

#include <type_traits> 

template<typename T> 
void foo(T&&) 
{ 
    static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!"); 
    // ... 
} 

कौन सा तथ्य पर निर्भर करता है कि जब प्रकार X के lvalue पारित किया जा रहा है, TX& होने के लिए घटाया जाएगा।

तुम भी, एक बराबर SFINAE-बाधा इस्तेमाल कर सकते हैं यदि आप केवल एक प्रतिस्थापन विफलता का उत्पादन करना चाहते हैं: आप टेम्पलेट पैरामीटर के रूप में किसी न किसी प्रकार का इलाज जब

#include <type_traits> 

template<typename T, typename std::enable_if< 
    !std::is_reference<T>::value>::type* = nullptr> 
void foo(T&&) 
{ 
    // ... 
} 
+0

तो 'T &&' के लिए विशेषज्ञता क्यों है? सामान्य टेम्पलेट इस अधिकार को संभाल सकता है? –

+0

@ कौशिक: आपका प्राथमिक टेम्पलेट का मतलब है? ठीक है, अगर केवल प्राथमिक टेम्पलेट से ही अस्तित्व में है, तो 'remove_reference :: type' तुम वापस देना होगा' पूर्णांक && ' –

+0

हाँ बनाया सुधार। विशेषज्ञता में भी हमें वही अधिकार मिलता है? 'T && 'के लिए हमें' :: प्रकार' के लिए 'T &&' मिलता है? –

0

, सबसे "विशेष" विशेषज्ञता के लिए संकलक खोज करता है। आप इस टेम्पलेट, संकलक उपयोग remove_reference<T&&> संस्करण के लिए एक पूर्णांक & & पार कर लेते हैं। जनरल विशेषज्ञता आप देना नहीं है कि आप क्या चाहते हैं - यदि आप सामान्य specialiation को int&& पारित, टाइप हो जाएगा int&&

आप प्रकार मुद्रित करने के लिए चाहते हैं, typeid(some_type).name()

+0

मैंने टाइपिड का इस्तेमाल किया लेकिन जीसीसी में यह कुछ अजीब था। मुझे लगता है कि मुझे कुछ फ़िल्टर सही उपयोग करना है? टाइपिड के अलावा कोई संकलन समय सामान है? ताकि मैं static_assert के साथ उपयोग कर सकूं? –

+0

@ कौशिक: क्या आप प्रश्न के उस हिस्से को स्पष्ट कर सकते हैं? क्या आप एक स्ट्रिंग प्राप्त करना चाहते हैं जिसमें प्रकार का नाम शामिल है, या आप केवल यह सुनिश्चित करना चाहते हैं कि एक रावल्यू संदर्भ पारित किया गया हो? –

+0

@AndyProwl डीबग चरण के दौरान स्ट्रिंग प्राप्त करना अच्छा होगा और हां, मैं यह सुनिश्चित करना चाहता हूं कि केवल रावल्यू पारित हो गया था। अगर मैं इसे संकलित समय के दौरान प्राप्त कर सकता हूं तो यह सबसे उपयोगी है। –

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