2013-02-08 6 views
9

संपादित करें: मैं टीडीएम-जीसीसी-4.7.1-2 उपयोग कर रहा हूँ विंडोजtemplated अड्डों से एकाधिक विरासत टाइपिफ को कैसे असंबद्ध करने के लिए?

यह कैसे हल करने के लिए सुनिश्चित नहीं हैं। मैं इसे एक प्रकार की सूची सूची के रूप में उपयोग करना चाहता हूं जो मुझे बताएगा कि मैं B के टाइपपीफ में मौजूद किसी प्रकार का उपयोग करने का प्रयास नहीं कर रहा हूं।

template <typename T, typename U> 
struct A { 
    typedef pair<T, U> type; 
}; 

struct B : A<int, string>, A<int, float> {}; 

B::type foo; // won't compile, ambiguous reference, as expected 
B::A<int, int>::type bar; // compiles fine?? :(

वहाँ एक रास्ता यह A<int, int> पर विफल प्राप्त करने के लिए (और किसी भी अन्य A के B द्वारा विरासत में मिला नहीं), या किसी अन्य तरीके से इस बारे में जाने के लिए है? मुझे लगता है कि मैं tuple का उपयोग कर सकता हूं और is_same प्रत्येक तत्व पर तुलना करके जो भी मैं मेटाफंक्शन को खिलाता हूं, लेकिन यह आसान लग रहा था ... पहले: \

+0

मुझे शक है कि 'बी :: एक :: type' बिल्कुल संकलन चाहिए ...'बी :: ए' पहले से ही संदिग्ध है और टेम्पलेट का संदर्भ नहीं देता है, लेकिन उन क्षणों में से एक जिन्हें 'बी' प्राप्त होता है ... –

+0

@ डेविडरोड्रिगुएज़-ड्राईबीस मैं सहमत हूं, मुझे नहीं लगता कि यह क्यों संकलित करता है। मैं शायद मानक में दफन एक नियम लापता हूं। –

+0

मेरा मानना ​​है कि अनुभाग सी ++ 11 ड्राफ्ट में 14.6.1-4 है। स्पष्ट रूप से इस मामले की अनुमति देता है – jmetcalfe

उत्तर

6

यह इसलिए होता है क्योंकि वर्ग टेम्पलेट्स उसके खाका नाम इंजेक्शन है; इंजेक्शन नाम का उपयोग टेम्पलेट या टेम्पलेट तत्काल (14.6.1 पी 1) का जिक्र करते हुए एक प्रकार के रूप में किया जा सकता है। इंजेक्शन वर्ग का नाम तब व्युत्पन्न वर्ग (10.2 पी 5) द्वारा विरासत में लिया जाता है; इसे टेम्पलेट के रूप में उपयोग करना अस्पष्ट है (यह वही टेम्पलेट है हालांकि इसे विरासत में मिला है) इसलिए इसकी अनुमति है।

अपने कार्यक्रम को ठीक करने के लिए, is_base_of प्रयोग करके देखें:

struct B : A<int, string>, A<int, float> { }; 
template<typename T, typename U> 
using check_A = typename std::enable_if<std::is_base_of<A<T, U>, B>::value, A<T, U>>::type; 

check_A<int, float>::type bar1; // compiles 
check_A<int, int>::type bar2; // error 
+0

बेस चेक पर अच्छा कॉल! : डी धन्यवाद। –

2

§11.1/5 में, स्टैंडर्ड कहते हैं:

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

तो AB के दायरे में एक इंजेक्शन नाम है। यह §14.1/4 के अनुसार आधार वर्ग (क्योंकि यह संदिग्ध होगा) टेम्पलेट A को संदर्भित करता है।

बस A के दायरे की तरह, यदि आप केवल A कहते हैं, तो यह कक्षा ही है (लेकिन यह इस संदर्भ में टेम्पलेट है)। आप इस इंजेक्शन वाले नाम का उपयोग कर रहे हैं, और इसलिए B::A नाम ::A जैसा ही है। मुझे नहीं लगता कि इस व्यवहार को दबाने का एक तरीका है।

2

मानक स्पष्ट रूप से इसकी अनुमति देता है, हालांकि यह थोड़ा उलझन में है। मसौदे में 14.6.1-4 से:

एक लुक-अप पता चलता है कि एक इंजेक्शन-वर्ग-नाम (10.2) (उदाहरण के लिए, अगर यह एक से अधिक में पाया जाता है कुछ मामलों में एक अस्पष्टता में परिणाम कर सकते बेस क्लास)। यदि 0 इंजेक्शन-क्लास-नाम पाए गए सभी समान क्लास टेम्पलेट के विशेषज्ञताओं का संदर्भ लें, और यदि नाम टेम्पलेट-तर्क-सूची के बाद है, तो संदर्भ क्लास टेम्पलेट को संदर्भित करता है, न कि विशेषज्ञता इसके, और संदिग्ध नहीं है।

[ Example: 
template <class T> struct Base { }; 
template <class T> struct Derived: Base<int>, Base<char> { 
typename Derived::Base b; // error: ambiguous 
typename Derived::Base<double> d;// OK 
}; 
— end example ] 
संबंधित मुद्दे