2017-09-05 7 views
13

की C++ 17 पैरामीटर कटौती में टेम्पलेट कारण अस्पष्टता पर विचार करें:एक साधारण उदाहरण के निर्माता सकते हैं वर्ग टेम्पलेट

template <class T> 
struct foo { 
    template <template <class> class TT> 
    foo(TT<T>&&) {} 
    foo(foo<T>&&){} 
    foo() {} 
}; 

int main() { 
    foo  f1(foo<int>{}); //case 1. 
    foo<int> f2(foo<int>{}); //case 2. 
} 

प्रकरण बजना में foo वर्ग के टेम्पलेट तर्क कटौती में 1. कारणों अस्पष्टता लेकिन जीसीसी में नहीं । मैंने सोचा कि टेम्पलेट फ़ंक्शंस (यहां - कन्स्ट्रक्टर) को ओवरलोड रिज़ॉल्यूशन में कम प्राथमिकता है। क्या यह मामला यहां नहीं है?

त्रुटि संदेश:

prog.cc:10:14: error: ambiguous deduction for template arguments of 'foo' 
    foo  f1(foo<int>{}); //case 1. 
      ^
prog.cc:4:5: note: candidate function [with T = int, TT = foo] 
    foo(TT<T>&&) {} 
    ^
prog.cc:5:5: note: candidate function [with T = int] 
    foo(foo<T>&&){} 
    ^
1 error generated. 

[clang demo][gcc demo]

उत्तर

11

यह एक क्लैंग बग है। तथ्य यह है कि उम्मीदवारों का सेट c'tors से बनता है, यह असंभव होना चाहिए, क्योंकि उम्मीदवार सेट बनने के बाद, पूर्ण रूपांतरण अनुक्रमों और टेम्पलेट फ़ंक्शन ऑर्डरिंग के क्रम में समान नियमों का उपयोग करके सर्वोत्तम अधिभार चुना जाता है।

[over.match.funcs]/1 के शब्दों में:

[over.match.funcs] की subclauses उम्मीदवार कार्यों का सेट और तर्क सूची में संकल्प ओवरलोड प्रस्तुत सात संदर्भों का वर्णन किया है जो अधिभार में संकल्प का उपयोग किया जाता है। इन उपखंडों में परिभाषित स्रोत परिवर्तन और निर्माण केवल ओवरलोड रिज़ॉल्यूशन प्रक्रिया का वर्णन करने के उद्देश्य से हैं। ऐसे परिवर्तनों का उपयोग करने के लिए एक कार्यान्वयन की आवश्यकता नहीं है और निर्माण।

यह स्पष्ट रूप से बताता है कि ओवरलोड रिज़ॉल्यूशन प्रक्रिया हमेशा समान होती है। एकमात्र अंतर यह है कि उम्मीदवार सेट कैसे बनाया जाता है।

और के रूप में द्वारा [over.match.class.deduct]/1

निर्दिष्ट कार्य करता है और समारोह टेम्पलेट्स का एक सेट का निर्माण होता है शामिल:

  • टेम्पलेट नाम से नामित प्राथमिक वर्ग टेम्पलेट में से प्रत्येक के निर्माता के लिए, यदि टेम्पलेट को परिभाषित किया गया है, के साथ एक फ़ंक्शन टेम्पलेट निम्न गुण:

    • टेम्पलेट पैरामीटर कन्स्ट्रक्टर के टेम्पलेट पैरामीटर (डिफ़ॉल्ट टेम्पलेट तर्क सहित) के बाद क्लास टेम्पलेट के टेम्पलेट पैरामीटर हैं, यदि कोई हो।

    • फ़ंक्शन पैरामीटर के प्रकार कन्स्ट्रक्टर के प्रकार हैं।

    • रिटर्न प्रकार क्लास टेम्पलेट से प्राप्त टेम्पलेट पैरामीटर से संबंधित टेम्पलेट-नाम और टेम्पलेट तर्कों द्वारा नामित क्लास टेम्पलेट विशेषज्ञता है।

प्रत्येक c'tor उम्मीदवार सेट में एक छद्म समारोह का परिचय देंगे। इस तरह:

template <class T>       foo(foo<T>&&) -> foo<T> 
template <class T, template<class> class TT> foo(TT<T>&&) -> foo<T> 

बेहतर तरीके से समझने के लिए, अगर यह एक नि: शुल्क समारोह था bar:

template <template <class> class TT, class T> 
void bar(TT<T>&&) {} 

template <class T> 
void bar(foo<T>&&){} 

फिर टेम्पलेट समारोह आदेश पहले अधिभार दूसरे की तुलना में कम कर देगी।

+0

आप सही हो सकते हैं, लेकिन मैं एक मानक रेफरी से खुश हूं। एमएसवीसी भी इस पर बमबारी करता है। संपादित करें: आपने मुझे इसे हराया। धन्यवाद। – AndyG

+1

कॉपी कटौती उम्मीदवार के बारे में क्या? –

+0

@VaughnCato - यह सूची में अगली गोली है। लेकिन मुझे नहीं लगता कि यह इस बात से संबंधित है कि यह संदिग्ध होना चाहिए या नहीं। – StoryTeller

1

वे कम प्राथमिकता नहीं है। आप SFINEA का उपयोग कर समस्या का समाधान कर सकते हैं। यह स्कॉट मेयर्स से प्रभावी आधुनिक सी ++ में वर्णित है।

template <class T> 
struct foo { 
    template <template <class> class TT, class = std::enable_if_t<!std::is_same_v<foo<T>, std::decay_t<TT<T>>>>> 
    foo(TT<T>&&) {} 
    foo(foo<T>&&){} 
    foo() {} 
}; 
+0

संदर्भ? ऑर्डरिंग नियम स्पष्ट हैं अगर यह एक फ्री फ़ंक्शन कॉल था। – StoryTeller

+0

मैंने उत्तर –

+3

संख्या का संदर्भ जोड़ा, मेरा मतलब मानक संदर्भ में था। मैंने मायर्स की किताब पढ़ी और यह इसके द्वारा कवर नहीं है। आप यहां विभिन्न चीजों को भंग कर रहे हैं। – StoryTeller

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