2017-12-27 95 views
23

निम्नलिखित पर विचार करें अधिक स्थिरांक संदर्भ लेती है:खाका स्थिरांक सूचक

template <class T> void Foo(const T* x) { 
    std::cout << "I am the pointer overload" << std::endl; 
} 

template <class T> void Foo(const T& x) { 
    std::cout << "I am the reference overload" << std::endl; 
} 

ऊपर देखते हुए, मैं निम्नलिखित कॉल करने के लिए सूचक अधिभार उम्मीद करेंगे:

int* x; 
Foo(x); 

लेकिन ऐसा नहीं है। ऐसा लगता है कि const T* के रूप में मुझे अजीब लगता है कि एक गैर-कॉन्स T के साथ-साथ const T& भी स्पष्ट रूप से बाध्य हो सकता है लेकिन पॉइंटर संस्करण "बेहतर फिट" जैसा प्रतीत होता है।

मेरे आवेदन के लिए मैं पॉइंटर संस्करण कहलाता हूं। मैं एक अतिरिक्त विशेषज्ञता के माध्यम से यह काम कर सकता हूं:

template <class T> void Foo(T* x) { 
    const T* const_x = x; 
    Foo(const_x); 
} 

लेकिन यह गलत और अनावश्यक लगता है। क्या कोई बेहतर तरीका है? मैं समझ नहीं पा रहा हूं (मानक के अनुभाग x.y.z के अलावा यह कहता है कि यह इस तरह है)?

+10

"लेकिन सूचक संस्करण की तरह लगता है एक" बेहतर फिट "" - 'क्यों स्थिरांक पूर्णांक *' एक की तरह लग 'int * const 'से बेहतर फिट? – hvd

+3

यदि आप फ़ंक्शन प्रिंट 'x' रखने का प्रयास करते हैं तो आप कम उलझन में होते। – StoryTeller

+1

बस टेम्पलेट शून्य फू (कॉन्स टी एंड एक्स) { std :: cout << "मैं संदर्भ अधिभार हूं" << std :: endl; } यह हमेशा पॉइंटर संस्करण को कॉल करेगा :) –

उत्तर

25

आप सोच रहे हैं: यदि मेरा पैरामीटर स्थिर नहीं होगा (या यदि तर्क स्थिर रहेगा) तो सूचक एक सही मैच होगा। यह सही है। मेरे पास जो अंतर है वह const है। तो बस उपरोक्त परिदृश्य में const जोड़ना मुझे पॉइंटर ओवरलोड के साथ-साथ मिलना चाहिए। यह भी सही है। अब जब से आप स्पष्ट रूप से संदर्भ अधिभार प्राप्त कर सकते हैं तब से यह कैसे हो सकता है? खैर, कोड आपके विचार से मेल नहीं खाता है। const की जगह पर

template <class T> void Foo(T* const x);  
template <class T> void Foo(T const &x); 

वेतन ध्यान: यहाँ कोड है कि सोच की अपनी लाइन के साथ जाना होगा और कहा कि वास्तव में सूचक अधिभार का चयन होता है। मैंने शीर्ष स्तर क्वालीफायर के रूप में const जोड़ा है। जबकि T const &x आपके पास const T& x, T* const x के बराबर है const T* x जैसा नहीं है।

चलें इस मामले में अधिभार संकल्प देखें:

fun          | T | parameter | argument 
-----------------------------------------+------+--------------+----------- 
template <class T> void Foo(const T* x) | int | const int* | int* 
template <class T> void Foo(T const &x) | int* | int* const & | int* 

आप पहले संस्करण में देख बस जोड़ने एक शीर्ष स्तर स्थिरांक है सकते हैं:

fun          | T | parameter | argument 
-----------------------------------------+------+--------------+----------- 
template <class T> void Foo(T* const x) | int | int* const | int* 
template <class T> void Foo(T const &x) | int* | int* const & | int* 

अपने संस्करण के साथ अधिभार देखते हैं पसंदीदा और पॉइंटर अधिभार चुना जाता है। कोई सूचक रूपांतरण आवश्यक नहीं है।

दूसरे मामले में पॉइंटर अधिभार को pointer to mutable से pointer to const पर सूचक रूपांतरण की आवश्यकता होगी। वे विभिन्न प्रकार के पॉइंटर्स हैं। लेकिन दूसरे अधिभार के साथ कोई सूचक रूपांतरण आवश्यक नहीं है। बस एक शीर्ष स्तर const जोड़ना।

यह संक्षेप सबसे अच्छा मैं जाए बिना समझा सकते हैं कि क्या मानक के xyz खंड कहते हैं

+0

ओवरलोड रिज़ॉल्यूशन के दौरान फंक्शन तर्क घोषणा में शीर्ष-स्तर 'const' को अनदेखा किया जाता है। तो 'टेम्पलेट शून्य फू (टी * कॉन्स एक्स);' और 'टेम्पलेट शून्य फू (टी * एक्स);' समकक्ष फ़ंक्शन टेम्पलेट घोषणाएं हैं। – Constructor

4

आपकी समस्या यह है कि जब Foo(x); संकलन एक टेम्पलेट प्रकार कटौती निष्पादित किया जाएगा है, और के रूप में अपने एक्स है में है int* इसे पहले Foo<int*>(x) कॉल के रूप में व्याख्या किया जाएगा और आपके template <class T> void Foo(const T& x) ओवरलोड इसके लिए एकदम सही मिलान है, इसलिए कटौती टाइप करें यहां टाइप करें।

यदि आप कक्षाओं (टेम्पलेट फ़ंक्शंस के बजाय) से निपटेंगे तो आप पॉइंटर-प्रकार और गैर-पॉइंटर-प्रकारों को अलग करने के लिए आंशिक टेम्पलेट विशेषज्ञता का उपयोग कर सकते हैं लेकिन कार्यों के लिए केवल पूर्ण विशेषज्ञता की अनुमति है।

आप क्या कर सकते की तरह SFINAE तकनीक का उपयोग करने के लिए है:

template <class T> void Foo(const T* x) { 
    std::cout << "I am the pointer overload" << std::endl; 
} 

template <class T> 
typename std::enable_if<!std::is_pointer<T>::value>::type 
Foo(const T& x) { 
    std::cout << "I am the reference overload" << std::endl; 
} 

इस मामले में संदर्भ अधिभार (जब प्रकार की कटौती) से मेल नहीं होगा अगर टी आ सूचक प्रकार है, इसलिए संकलक Foo<int>(x) की कोशिश करेंगे साथ ही और आपके template <class T> void Foo(const T* x) अधिभार एक आदर्श मैच होगा (बस आपने जो अपेक्षा की है)।

नमूना:

int x = 12; 
int* pX = new int(5); 

Foo(x); 
Foo(pX); 

उत्पादन:

I am the reference overload 
I am the pointer overload 
+0

"और जैसा कि आपका एक्स एक int * है, इसे पहले 'Foo (x)' कॉल" के रूप में व्याख्या किया जाएगा। ऐसा नहीं है कि टेम्पलेट तर्क कटौती कैसे काम करती है। कंपाइलर फ़ंक्शन तर्क के प्रकार को टेम्पलेट तर्क के रूप में उपयोग नहीं करता है और देखता है कि यह फिट बैठता है या नहीं। यह चारों तरफ काम करता है - प्रत्येक टेम्पलेट अधिभार के लिए, यह टी को अपने फ़ंक्शन घोषणा और दिए गए फ़ंक्शन तर्क के आधार पर टी को कम करने का प्रयास करता है। इस मामले में, यह 'Foo (int const *) 'और' Foo (int * const &) 'को घटाएगा। 'Int *', 'int * const '' गुजरते समय 'int const *' से बेहतर मिलान होगा क्योंकि इसमें कोई सूचक रूपांतरण की आवश्यकता नहीं होती है। – oisyn

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