2010-09-08 8 views
7

मैं एक वेक्टर लाइब्रेरी तैयार कर रहा हूं और एक स्नैग मारा है। मैं रिकर्सिव वैक्टर (यानी vec<H,vec<W,T> >) को अनुमति देना चाहता हूं, इसलिए मैं अपने "मिनट" और अन्य कार्यों को भी रिकर्सिव करना चाहता हूं। यहां मेरे पास है:सी ++ को एक गैर-बदसूरत तरीके से सही टेम्पलेट विधि को कॉल करें

template<typename T> 
inline T min(const T& k1, const T& k2) { 
return k1 < k2 ? k1 : k2; 
} 
template<int N, typename T, typename VT1, typename VT2> 
inline vec<N,T> min(const container<N,T,VT1>& v1, const container<N,T,VT2>& v2) { 
vec<N,T> new_vec; 
for (int i = 0; i < N; i++) new_vec[i] = min(v1[i], v2[i]); 
return new_vec; 
} 

... 

template<int N, typename T> 
class vec : public container<N,T,vec_array<N,T> > { 

... 

// This calls the first (wrong) method and says you can't call ? on a vec 
vec<2,float> v1,v2; 
min(v1,v2); 
// This says the call is ambiguous 
container<2,float,vec_array<2,float> > c1,c2; 
min(c1,c2); 
// This one actually works 
vec<2,float> v3; container<N,T,some_other_type> v4; 
min(v3,v4); 
// This works too 
min<2,float,vec_array<2,float>,vec_array<2,float> >(v1, v2); 

वह अंतिम कॉल बदसूरत है! मैं सिर्फ min(v1,v2) के साथ सही विधि कैसे कॉल कर सकता हूं? सबसे अच्छा मैं "वीसी" वर्ग से छुटकारा पाने के लिए आ सकता हूं (इसलिए v1 और v2 को कंटेनर < 2, फ्लोट, vec_array < 2, फ्लोट>>) के रूप में परिभाषित किया जाना चाहिए और एक और template<N,T,VT> मिनट विधि को कॉल करें min<N,T,VT,VT>(v1,v2)

धन्यवाद!

+0

'कंटेनर' टेम्पलेट कैसा दिखता है? – Chubsdad

+0

कंटेनर वास्तव में सरल है। इसमें एक सदस्य है, "वीटी _vec", और एक [] ऑपरेटर को परिभाषित करता है जो सिर्फ _vec [i] को कॉल करता है। – Chris

+0

अपने फ़ंक्शन 'मिनट' के लिए एक अलग नाम का उपयोग करने का प्रयास करें उदा। 'Mymin'। मुझे लगता है कि std :: min के साथ ओवरलोड रिज़ॉल्यूशन आपको दुःस्वप्न दे रहा है – Chubsdad

उत्तर

0
template<typename T1, **typename T2**> 
inline T1 min(const T1& k1, **const T2&** k2) { 
    return k1 < k2 ? k1 : k2; 
} 

... 

template<int N, typename T> 
struct vec { 
    typedef container<N,T,vec_array<N,T> > t; 
}; 


... 

vec<2,float>::t v1,v2; 
min(v1,v2); 

यही वह काम है जो मैंने इसे काम करने के लिए किया था।

अस्पष्टता इसलिए थी क्योंकि दोनों तर्कों का एक ही प्रकार है - container<2,float,vec_array<2,float> >min(const T&,const T&) विधि के लिए यह एक बिंदु है। चूंकि min(const container<N,T,VT1>& v1, const container<N,T,VT2>& v2) एक मैच और अधिक विशिष्ट है, इसलिए इसे एक अतिरिक्त बिंदु भी मिला है और संकलक इसका उपयोग करने के लिए अपना मन नहीं बना सकता है। दो प्रकार के तर्कों का उपयोग करने के लिए जेनेरिक मिनट को स्विच करना - न्यूनतम (कॉन्स टी 1 &, कॉन्स टी 2 &) - इसे जमा करने में धड़कता है।

मैंने vec<N,T> को गन्दा container<N,T,VT> सामान से निपटने के बिना विरासत के बजाय "टेम्पलेट टाइपपीफ" का उपयोग करने के लिए भी स्विच किया। यह vec<N,T>::t सही फ़ंक्शन के लिए सटीक मिलान बनता है।

अब मैं विरासत के बजाय टाइपिफ़ का उपयोग कर रहा हूं और केवल एक के बजाय जेनेरिक मिनट फ़ंक्शन में दो प्रकार का उपयोग कर रहा हूं, सही विधि कहला रही है।

1

आपके पास एक अधिभार रिज़ॉल्यूशन होगा जो पहले मामले के लिए पहले min को पसंद करता है। यह दोनों सटीक मिलान से तर्क स्वीकार करता है, जबकि दूसरे min को तर्क स्वीकार करने के लिए मूल रूपांतरण के लिए व्युत्पन्न की आवश्यकता होती है।

जैसा कि आपने बाद में (प्रयोग करके?) का उपयोग किया है, यदि आप व्युत्पन्न कक्षाओं के बजाय container<...> तर्क प्रकार के रूप में उपयोग करते हैं, तो इसे अब बेस रूपांतरण के लिए व्युत्पन्न की आवश्यकता नहीं होगी, और ओवरलोड रिज़ॉल्यूशन फिर दूसरा टेम्पलेट पसंद करेगा क्योंकि अन्यथा दोनों तर्कों को समान रूप से स्वीकार कर रहे हैं लेकिन दूसरा टेम्पलेट (आपके स्वयं के समाधान में) अधिक विशिष्ट है।

फिर भी अपने स्वयं के समाधान में, आपको समाधान मानक C++ बनाने के लिए वापसी प्रकार से पहले typename डालना होगा। मुझे लगता है कि आपको दूसरी टेम्पलेट को परिभाषित करने की आवश्यकता होने वाली समस्या यह है कि टेम्पलेट को और अधिक विशिष्ट बनाने के लिए, पहले मिनट min को उन सभी तर्कों को स्वीकार करने की आवश्यकता है जो दूसरे टेम्पलेट को स्वीकार करते हैं, जिसे बस मिलान करने का प्रयास करके पता लगाया जाता है पहले

container<N, T, VT1> -> T // func param 1 
container<N, T, VT2> -> T // func param 2 

के खिलाफ दूसरे टेम्पलेट के तर्कों तो, विभिन्न टेम्पलेट पैरामीटर प्रकार एक ही टेम्पलेट पैरामीटर है, जो एक संघर्ष का कारण और पहली टेम्पलेट सफलतापूर्वक दूसरी टेम्पलेट के सभी तर्क अनुमान नहीं कर देगा करने के लिए अनुमान की कोशिश करो।

container<N, T, VT> -> T // func param 1 
container<N, T, VT> -> T // func param 2 

यह पहली टेम्पलेट दूसरा टेम्पलेट से सभी पैरामीटर प्रकार अनुमान कर देगा, लेकिन नहीं दूसरी तरह के आसपास: container<N, T, VT> एक मनमाना से मेल नहीं खाएगी अपने स्वयं के समाधान के लिए, इस मामले नहीं होगा T।तो आपका स्वयं का समाधान का टेम्पलेट अधिक विशिष्ट है और इसे बुलाया जाता है, और फिर स्पष्ट रूप से अन्य टेम्पलेट के लिए आगे जाता है।

अंत में ध्यान दें कि आपका स्वयं का समाधान केवल कंटेनरों को स्वीकार करता है जहां तीसरा टेम्पलेट तर्क समान होता है, जबकि आपका अन्य min टेम्पलेट कंटेनर स्वीकार करता है जहां यह तर्क दोनों फ़ंक्शन तर्कों के लिए भिन्न हो सकता है। मुझे यकीन नहीं है कि यह उद्देश्य पर है - लेकिन अन्य min फ़ंक्शन में कार्य करता है जो संघर्ष करता है यदि आप ऊपर दिखाए गए अनुसार तीसरे तर्क प्रकार को समान नहीं बनाते हैं, तो मुझे यकीन नहीं है कि अन्यथा इसे कैसे ठीक किया जाए।


प्रश्नकर्ता बाद में, अपने ही जवाब संपादित तो ऊपर मेरी संदर्भ के सबसे करने के लिए "अपने खुद के जवाब" अब और लागू नहीं है।

+0

जोहान्स शाएब - litb: मैं अभी भी ओपी में दूसरे कॉल में अस्पष्टता के बारे में उलझन में हूं (जो मुझे लगता है कि बराबर है) टेम्पलेट संरचना ए {}; टेम्पलेट संरचना बी: ए {}; टेम्पलेट शून्य मिनट (टी स्थिरांक और एक, टी स्थिरांक एंड बी) {} टेम्पलेट शून्य मिनट (ए स्थिरांक और एक, एक स्थिरांक और ख) { } पूर्णांक मुख्य() { \t बी बी 1, बी 2; \t मिनट (बी 1, बी 2);} – Chubsdad

+0

@Chubsdad काफी नहीं है। दूसरे "मिनट" को 'टेम्पलेट <वर्ग टी, कक्षा यू> शून्य मिनट (ए कॉन्स और ए, ए कॉन्स और बी) को बदलने का प्रयास करें {} 'अब यह ओपी में अधिक है। आपके उदाहरण में, एक आदेश मौजूद है (जैसे कि प्रश्नकर्ता के अपने उत्तर के पहले संस्करण में, जहां उसके पास केवल * एक * 'VTx' पैरामीटर था, जो मैं अपने उत्तर में बात करता हूं। दुख की बात है कि उसने बाद में अपना जवाब पूरी तरह से बढ़ाया इसके संदर्भ में ज्यादातर बेकार हैं)। –

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