2009-07-10 12 views
7

हम एक उप-परियोजना 'commonUtils' है कि माता-पिता परियोजना भर में इस्तेमाल किया कई सामान्य कोड-स्निपेट हैं। एक ऐसी रोचक सामग्री मैंने देखा था: -परीक्षण करें कि एक वर्ग बहुरूपी है

/********************************************************************* 
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true. If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false 
*********************************************************************/ 
template <class T> 
bool isPolymorphic() { 
    bool answer=false; 
    typeid(answer=true,T()); 
    return answer; 
} 

मैं टिप्पणी माना जाता है और सोचा कि यह काफी एक दिलचस्प टेम्पलेट है, हालांकि यह परियोजना भर में उपयोग नहीं किया है। मैंने इसे जिज्ञासा के लिए इस तरह इस्तेमाल करने की कोशिश की ...

class PolyBase { 
public: 
    virtual ~PBase(){} 
}; 

class NPloyBase { 
public: 
    ~NBase(){} 
}; 


if (isPolymorphic<PolyBase>()) 
    std::cout<<"PBase = Polymorphic\n"; 
if (isPolymorphic<NPolyBase>()) 
    std::cout<<"NBase = Also Polymorphic\n"; 

लेकिन उनमें से कोई भी कभी भी सत्य नहीं लौटाता है। एमएसवीसी 2005 कोई चेतावनी नहीं देता है लेकिन कमौ ने चेतावनी दी है कि टाइपिड अभिव्यक्ति का कोई प्रभाव नहीं है। सी ++ मानक में धारा 5.2.8 कुछ भी नहीं कहता है जैसे टिप्पणी कहती है i.e. टाइपिड का मूल्यांकन गैर-पॉलीमोर्फिक प्रकारों के लिए संकलन समय पर और पॉलिमॉर्फिक प्रकारों के लिए रनटाइम पर किया जाता है।

1) तो मैं लगता है कि टिप्पणी भ्रामक/सादे गलत या के बाद से इस कोड के लेखक काफी वरिष्ठ सी ++ प्रोग्रामर है, मैं कुछ याद आ रही है?

2) OTOH, मैं अगर हम परीक्षण कर सकते हैं कि क्या एक वर्ग बहुरूपी है (कम से कम एक आभासी समारोह है) कुछ तकनीक का उपयोग कर सोच रहा हूँ?

3) जब एक जानना चाहते हो, तो एक वर्ग बहुरूपी है? ऐसे ही अनुमान लगाना; dynamic_cast<void*>(T) (dynamic_cast केवल पॉलिमॉर्फिक कक्षाओं पर काम करता है) का उपयोग कर कक्षा के प्रारंभ पते को प्राप्त करने के लिए।

अपनी राय प्रतीक्षा कर रहा है।

अग्रिम धन्यवाद,

+0

एर, यदि लेखक एक वरिष्ठ सी ++ प्रोग्रामर है तो आप पहले उसके साथ क्यों जांच नहीं करते? ... आप अक्सर अनुभवी लोगों से बहुत कुछ सीखेंगे। – stefanB

+9

ठीक है, अगर मैं इसे stackoverflow पर नहीं पूछ सकता था :-) – Abhay

उत्तर

8

मैं किसी भी संभव तरीके से कैसे कि typeid कि प्रकार की जांच करने के लिए इस्तेमाल किया जा सकता है कल्पना नहीं कर सकते बहुरूपी है। इसका इस्तेमाल यह भी करने के लिए नहीं किया जा सकता है कि यह है, क्योंकि टाइपिड किसी भी प्रकार पर काम करेगा। बूस्ट में कार्यान्वयन here है। क्यों यह आवश्यक हो सकता है - एक मामला मुझे पता है बूस्ट। सरलीकरण पुस्तकालय। यदि आप गैर-पॉलीमोर्फिक प्रकार को सहेज रहे हैं, तो आप इसे सहेज सकते हैं। यदि पॉलिमॉर्फिक को सहेजना है, तो आपको टाइपिड का उपयोग करके अपना डायनामिक टाइप प्राप्त करना होगा, और फिर उस प्रकार के लिए सीरियलाइजेशन विधि का आह्वान करना होगा (इसे कुछ तालिका में देखना)।

अद्यतन: ऐसा लगता है मैं वास्तव में गलत हूँ। इस संस्करण पर विचार करें:

template <class T> 
bool isPolymorphic() { 
    bool answer=false; 
    T *t = new T(); 
    typeid(answer=true,*t); 
    delete t; 
    return answer; 
} 

यह वास्तव में आपके मूल कोड स्निपेट में प्रति टिप्पणी के अनुसार नाम के रूप में काम करता है। टाइपिड के अंदर अभिव्यक्ति का मूल्यांकन नहीं किया जाता है यदि यह "पॉलिमॉर्फिक क्लास प्रकार के एक लाभा को निर्दिष्ट नहीं करता है" (std 3.2/2)। तो, उपरोक्त मामले में, यदि टी polymorphic नहीं है, तो टाइपिड अभिव्यक्ति का मूल्यांकन नहीं किया जाता है। यदि टी polymorphic है, तो * टी वास्तव में polymorphic प्रकार का lvalue है, तो पूरी अभिव्यक्ति का मूल्यांकन किया जाना चाहिए।

अब, आपका मूल उदाहरण अभी भी गलत है :-)। यह T() का उपयोग किया गया, *t नहीं। और T()रैवल्यू (std 3.10/6) बनाएं। तो, यह अभी भी एक अभिव्यक्ति उत्पन्न करता है जो "पॉलिमॉर्फिक वर्ग का लालसा" नहीं है।

यह काफी दिलचस्प चाल है। दूसरी तरफ, इसका व्यावहारिक मूल्य कुछ हद तक सीमित है - क्योंकि बूस्ट :: is_polymorphic आपको एक संकलन-समय स्थिर देता है, यह आपको रन-टाइम मान देता है, इसलिए आप पॉलिमॉर्फिक और गैर-पॉलीमोर्फिक प्रकारों के लिए अलग-अलग कोड को तुरंत चालू नहीं कर सकते ।

+0

हां मैं बूस्ट कार्यान्वयन को जानता हूं जो लगभग आकार() तकनीक का उपयोग करता है। Serialization tidbit के लिए धन्यवाद। मुझे यह जानने में दिलचस्पी थी कि क्या आम बात यह है कि टेम्पलेट सबसे पहले सही है और दूसरी बात यह है कि यह परियोजना में संरक्षित है। – Abhay

+2

आह हे, वास्तव में एक दिलचस्प चाल है, लेकिन 3.10/6 का आपका उद्धरण प्रबुद्ध था, धन्यवाद। बाइनरी-आकार के मामलों में या टेम्पलेट आकार में चुन सकते हैं जब उपयोगकर्ता को पॉलिमॉर्फिक कक्षा में वर्चुअल डॉटर प्रदान करने पर भरोसा नहीं किया जाता है। हां मैं 2 बार ऊपर नहीं उठा सकता! – Abhay

3


class PolyBase { 
public: 
    virtual ~PolyBase(){} 
}; 

class NPolyBase { 
public: 
    ~NPolyBase(){} 
}; 

template<class T> 
struct IsPolymorphic 
{ 
    struct Derived : T { 
     virtual ~Derived(); 
    }; 
    enum { value = sizeof(Derived)==sizeof(T) }; 
}; 


void ff() 
{ 
    std::cout << IsPolymorphic<PolyBase >::value << std::endl; 
    std::cout << IsPolymorphic<NPolyBase>::value << std::endl; 
} 

+1

मुझे यकीन नहीं है कि यह पूरी तरह मूर्खतापूर्ण है या नहीं। एक कंपाइलर उप-ऑब्जेक्ट्स के बीच पैडिंग जोड़ सकता है जिसमें केस आकार() चाल काम नहीं करेगी। – Abhay

+1

यह कहता है कि व्युत्पन्न कहता है कि व्युत्पन्न अपने सदस्य चर को परिभाषित करता है, जिससे इसे अव्यवहारिक बना दिया जाता है। – Indy9000

+0

@Indeera: आप किसी भी सदस्य चर को नहीं जोड़ेंगे क्योंकि व्युत्पन्न संरचना जानबूझकर आपके द्वारा निर्दिष्ट कक्षा से सार्वजनिक रूप से प्राप्त होती है। एकमात्र चेतावनी यह है कि यदि निर्दिष्ट कक्षा में वर्चुअल डॉटर नहीं है लेकिन पैडिंग समस्या के अलावा कुछ आभासी funcs (जिसमें निर्दिष्ट कक्षा अभी भी polymorphic है)। बूस्ट मानता है कि एक पॉलिमॉर्फिक क्लास वर्चुअल डॉटोर को परिभाषित करता है और मुझे लगता है कि कुछ कंपाइलर विनिर्देशों का उपयोग करके पैडिंग को संभालता है। – Abhay

-1

मैं यहां थोड़ा उलझन में हूं, और इस उत्तर पर कुछ टिप्पणियां प्राप्त करने की उम्मीद कर रहा हूं कि मुझे क्या याद आ रहा है।

निश्चित रूप से यदि आप यह जानना चाहते हैं कि कोई वर्ग पॉलिमॉर्फिक है या नहीं, तो आपको यह पूछना है कि यह dynamic_cast का समर्थन करता है, है ना?

template<class T, class> struct is_polymorphic_impl : false_type {}; 
template<class T> struct is_polymorphic_impl 
    <T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {}; 

template<class T> struct is_polymorphic : 
    is_polymorphic_impl<remove_cv_t<T>, void*> {}; 

क्या कोई इस कार्यान्वयन में कोई दोष दिखा सकता है? मुझे लगता है कि एक होना चाहिए, या अतीत में किसी बिंदु पर होना चाहिए, क्योंकि the Boost documentation का दावा है कि is_polymorphic "सी ++ भाषा में पोर्टेबल रूप से लागू नहीं किया जा सकता"।

लेकिन "पोर्टेबल" एक वीज़ल शब्द है, है ना? हो सकता है कि वे सिर्फ एमएसवीसी अभिव्यक्ति-एसएफआईएनएई का समर्थन नहीं करते हैं, या एंबेडेड सी ++ जैसी कुछ बोलियां dynamic_cast का समर्थन नहीं करती हैं। हो सकता है कि जब वे "सी ++ भाषा" कहें तो उनका मतलब है "सी ++ भाषा का सबसे कम-आम-संप्रदाय सबसेट।" लेकिन मुझे एक घबराहट संदेह है कि शायद उनका मतलब है कि वे क्या कहते हैं, और मैं हूं जो कुछ खो रहा है।

ओपी में typeid दृष्टिकोण (के रूप में नहीं एक lvalue एक rvalue उपयोग करने के लिए एक बाद की जवाब द्वारा संशोधित) भी ठीक लग रहा है, लेकिन निश्चित रूप से यह constexpr नहीं कर रहा है और यह वास्तव में एक T है, जो सुपर महंगा हो सकता है के निर्माण की आवश्यकता है। तो यह dynamic_cast दृष्टिकोण बेहतर लगता है ... जब तक कि यह किसी कारण से काम नहीं करता है। विचार?

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