2012-06-17 32 views
13

के बिना कक्षा पहचान मुझे सी ++ RTTI के बिना अंतर्निहित पहचान कक्षा में इंटरनेट पर कहीं भी एक सरल समाधान मिला है।आरटीटीआई

template <typename T> 
class Identity { 
public: 
    static int64_t id() 
    { 
     static int64_t dummy; 
     return reinterpret_cast<int64_t>(&dummy); 
    } 
}; 

जब हम कुछ वर्ग आईडी की जरूरत है, हम बस का उपयोग करें:

Identity<OurClass>::id(); 

मैं सोच रहा हूँ, वहाँ किसी भी टकराव से कर रहे हैं? क्या यह अलग-अलग वर्गों, या एक ही कक्षा के लिए अलग-अलग आईडी के लिए एक ही आईडी वापस कर सकता है? मैंने इस कोड को विभिन्न अनुकूलन मूल्यों के साथ g ++ के साथ करने की कोशिश की है, सब कुछ ठीक लगता है।

+0

सिद्धांत रूप में, हाँ। इस बात की कोई गारंटी नहीं है कि एक फ़ंक्शन पॉइंटर एक 'int' के समान आकार है। –

+1

यह मेरी रुचियों के लिए प्रासंगिक है ... –

+0

उपर्युक्त समस्या से बचने के लिए, उस स्थिर सदस्य फ़ंक्शन टेम्पलेट में स्थिर 'int' चर डालना बेहतर होगा और * उस * पर एक सूचक वापस लौटना बेहतर होगा। संकलक वैसे भी समारोह को अनुकूलित करेगा। – Electro

उत्तर

12

सबसे पहले: भी व्यवहार में, हालांकि,

  • intptr_t
  • और सी ++ 11 uintptr_t

दूसरा में: इस तरह के एक अभिन्न प्रकार है कि विशेष रूप से किया जाता है संकेत को रोकने के लिए है जीसीसी पर वे बराबर हैं, किसी ऑब्जेक्ट के लिए पॉइंटर का आकार और फ़ंक्शन पॉइंटर (या सदस्य के लिए पॉइंटर) का आकार अलग-अलग हो सकता है। इसलिए यह विधि के बजाय (मानक अनुरूपता के लिए) के बजाय एक विशिष्ट वस्तु का उपयोग करना बेहतर होगा।

तीसरा, यह केवल आपको पहचान देता है, जबकि आरटीटीआई बहुत अधिक समृद्ध है, क्योंकि यह सभी उप-वर्गों के बारे में जानता है, किसी दिए गए ऑब्जेक्ट को कास्ट किया जा सकता है, और यहां तक ​​कि क्रॉस-कास्ट या आभासी विरासत में भी अनुमति देता है।

फिर भी, सही संस्करण उपयोगी मुझे लगता है कि हो सकता है:

struct Foo { 
    static intptr_t Id() { 
     static boost::none_t const Dummy = {}; 
     return reinterpret_cast<intptr_t>(&Dummy); 
    } 
}; 

और पदानुक्रम में, कि आईडी लौटने एक virtual समारोह हो रही है।

पूर्णता के लिए, मैं उल्लेख करूंगा कि क्लैंग और एलएलवीएम के पास आरटीटीआई के बिना ऑब्जेक्ट पहचान से निपटने का अपना तरीका है। आप isa, cast और dyn_casthere लागू करने के अपने तरीके के बारे में पढ़ना चाह सकते हैं।

+0

उपरोक्त। – Electro

+0

धन्यवाद, लेकिन मुझे नहीं मिला, एक ऑब्जेक्ट के लिए पॉइंटर का आकार और फ़ंक्शन पॉइंटर का आकार अलग क्यों हो सकता है? क्या आप एक उदाहरण दे सकते हैं? – pproger

+0

@ प्रप्रोगर: आभासी सदस्य फ़ंक्शन पॉइंटर्स का आकार अक्सर नियमित पॉइंटर्स से आकार में भिन्न होता है। हालांकि यह संकलक विशिष्ट है, आप इस उत्कृष्ट कोडप्रोजेक्ट आलेख में इसके बारे में और अधिक पढ़ सकते हैं: http://www.codeproject.com/Articles/7150/Member- फ़ंक्शन- पॉइंटर्स- और- सबसे- संभावित –

-1

यह समाधान एक फ़ंक्शन पॉइंटर को int पर रखता है। इस बात की कोई गारंटी नहीं है कि यह सूचक int में फिट बैठता है, हालांकि अभ्यास में sizeof(void *) == sizeof(void (*)()) <= sizeof(int)

संपादित करें: मेरा बुरा। X86_64 sizeof(int) = 4, sizeof(void (*)()) = 8 पर, इसलिए टकराव संभव हैं और अप्रत्याशित हैं।

आप उचित आकार के अभिन्न अंग में डाले जा सकते हैं, लेकिन फिर भी यह सैद्धांतिक रूप से अपरिभाषित व्यवहार है।

+0

यह अभ्यास में हमेशा सत्य नहीं है; x86-64 पर आज़माएं। –

+0

ठीक है, मैंने कोड संपादित किया है। अब क्या? व्यापक स्पष्टीकरण के लिए – pproger

0

इस संस्करण अपरिभाषित व्यवहार (और संकलक चेतावनी) से बचा जाता है:

template <typename T> 
class Identity { 
public: 
    static const int* id() { static const int id = 0; return &id; } 
}; 
+0

मुझे सूचक मूल्य के रूप में वापसी मूल्य की आवश्यकता नहीं है। मैं int चाहता हूँ :) – pproger

+0

आप परवाह क्यों है कि यह एक सूचक है या नहीं? – Electro

+0

मैं नहीं करता। कोड के लेखक) – pproger