2012-03-09 6 views
12

मैं आश्चर्यचकित था निम्नलिखित कोड एक could not deduce template argument for T त्रुटि हुई:संकलक टेम्पलेट प्रकार को डिफ़ॉल्ट तर्कों से क्यों नहीं हटा सकता?

struct foo 
{ 
    template <typename T> 
    void bar(int a, T b = 0.0f) 
    { 
    } 
}; 

int main() 
{ 
    foo a; 
    a.bar(5); 

    return 0; 
} 

a.bar<float>(5) फिक्स मुद्दा कॉलिंग। संकलक डिफ़ॉल्ट तर्क से प्रकार को क्यों नहीं हटा सकता?

A template type-parameter cannot be deduced from the type of a function default argument.

सी ++ 11 में:

उत्तर

15

सी ++ 03 में, विनिर्देश स्पष्ट रूप से एक टेम्पलेट तर्क (सी ++ 03 §14.8.2/17) निकालना उपयोग किए जाने से डिफ़ॉल्ट तर्क पर प्रतिबंध लगाता है हालांकि

template <typename T = float> 
void bar(int a, T b = 0.0f) { } 

डिफ़ॉल्ट टेम्पलेट तर्क की आवश्यकता है,:, आप समारोह टेम्पलेट के लिए एक डिफ़ॉल्ट टेम्पलेट तर्क दे सकता है। यदि डिफ़ॉल्ट टेम्पलेट तर्क प्रदान नहीं किया गया है, तो डिफ़ॉल्ट फ़ंक्शन तर्क अभी भी टेम्पलेट तर्क कटौती के लिए उपयोग योग्य नहीं है। विशेष रूप से, निम्न लागू होता है (सी ++ 11 14.8.2.5/5):

The non-deduced contexts are:

...

  • A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
+10

कह रहे हैं "क्योंकि मानक कहता है" एक वैध उत्तर है, इसके पीछे तर्क जानना अच्छा लगेगा। –

+1

अन्य कारणों से, फ़ंक्शन की अलग-अलग घोषणाएं अलग-अलग डिफ़ॉल्ट तर्क घोषित कर सकती हैं (मैं निश्चित रूप से फ़ंक्शन टेम्पलेट्स पर लागू होता हूं।) –

+1

@ जेम्स: नहीं, अलग-अलग घोषणाओं को विभिन्न डिफ़ॉल्ट तर्क घोषित करने की अनुमति नहीं है। यह एक ही तर्क के लिए एक ही डिफ़ॉल्ट देने के लिए कई घोषणाओं के लिए भी अनुमति नहीं है। 8.3.6 कहता है "बाद में घोषणा (एक ही मूल्य तक नहीं) द्वारा एक डिफ़ॉल्ट तर्क को फिर से नहीं किया जाएगा।" बेशक, यह केवल गैर-टेम्पलेट कार्यों पर लागू होता है। टेम्पलेट फ़ंक्शंस के लिए, ऐसा लगता है कि डिफ़ॉल्ट तर्क केवल आरंभिक घोषणा पर ही प्रदान किए जा सकते हैं। –

4

एक अच्छा कारण हो सकता है कि

void foo(bar, xyzzy = 0); 

भार के की एक जोड़ी के समान है। जब एक के रूप में लिखा अभी भी एक में दो कार्यों, जिनमें से न तो "पसंदीदा" है किसी भी अर्थ में तरह

void foo(bar b) { /* something other than foo(b, 0); */ } 
foo(bar, xyzzy); 

भी, यह है:

void foo(bar b) { foo(b, 0); } 
foo(bar, xyzzy); 

इसके अलावा, कभी कभी यह फायदेमंद ऐसे में यह refactor करने के लिए है । आप एक-तर्क फ़ंक्शन को कॉल कर रहे हैं; दो तर्क एक प्रभावशाली ढंग से एक अलग कार्य है। डिफ़ॉल्ट तर्क नोटेशन सिर्फ उन्हें एक में विलीन करता है।

यदि ओवरलोडिंग उस व्यवहार के लिए होती है जिसे आप पूछ रहे हैं, तो स्थिरता के लिए इसे उस मामले में काम करना होगा जब टेम्पलेट दो परिभाषाओं में विभाजित हो। इससे कोई फर्क नहीं पड़ता क्योंकि कटौती एक असंबंधित कार्य से प्रकार खींच रही है जिसे बुलाया नहीं जा रहा है! और यदि इसे कार्यान्वित नहीं किया गया था, तो इसका अर्थ यह होगा कि विभिन्न पैरामीटर सूची की लंबाई को ओवरलोड करना "डिफ़ॉल्ट-तर्क" की तुलना में "द्वितीय श्रेणी नागरिक" बन जाता है।

यह अच्छा है अगर ओवरलोड और डिफॉल्टिंग के बीच का अंतर क्लाइंट को पूरी तरह छुपाया जाता है।

7

सामान्य रूप से प्राप्त करने में कुछ तकनीकी कठिनाइयां होंगी। याद रखें कि टेम्पलेट्स में डिफ़ॉल्ट तर्क तब तक तत्काल नहीं होते जब तक उनकी आवश्यकता न हो। तो विचार करें:

template<typename T, typename U> void f(U p = T::g()); // (A) 
template<typename T> T f(long, int = T()); // (B) 
int r = f<int>(1); 

इस के लिए निम्न चरण (अन्य बातों के अलावा) प्रदर्शन से आज हल हो गई है: उम्मीदवारों के लिए टेम्प्लेट पैरामीटर (ए) और (बी) निकालना

  1. का प्रयास करना; यह (ए) के लिए विफल रहता है, जिसे इसलिए हटा दिया जाता है।
  2. ओवरलोड रिज़ॉल्यूशन निष्पादित करें; (बी) कॉल चयन किया जाता है
  3. रूप है, डिफ़ॉल्ट तर्क

instantiating आदेश एक डिफ़ॉल्ट तर्क से अनुमान करने के लिए, कि डिफ़ॉल्ट तर्क ही कटौती प्रक्रिया को पूरा करने से पहले instantiated करना होगा। यह असफल हो सकता है, जिससे SFINAE संदर्भ के बाहर त्रुटियां आती हैं। यानी, एक उम्मीदवार जो कॉल के लिए पूरी तरह अनुचित हो सकता है, एक त्रुटि उत्पन्न कर सकता है।

+0

के साथ पहले को उचित लगता है। –

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

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