2009-02-20 8 views
13

मैं एक और एक Column वर्ग घोषित करने के लिए प्रयास कर रहा हूँ एक निजी std::map एक टेम्प्लेटेड Column की ओर इशारा करते मूल्यों के साथ होने के साथ। कुछ इस तरह:सी ++ std :: टेम्पलेट श्रेणी के नक्शे को महत्व देता

template <typename T> 
class DataType { 
    private: 
    T type; 
}; 
template <typename T> 
class Field { 
    private: 
    T value; 
    DataType<T> value; 
}; 
class Row { 
    private: 
    std::map<unsigned long,Field*> column; 
}; 

ठीक है, मैं सिद्धांत रूप में लगता है वर्ग नहीं होना चाहिए पता करने के लिए Field (या Column) किस तरह हम उपयोग करने के लिए, यानी कि क्या यह है करना चाहते हैं एक Field<int> स्तंभ 1 में या Field<double> कॉलम 2 में। लेकिन मुझे यकीन नहीं है कि Row::column घोषणा के लिए सही वाक्यविन्यास क्या है, या यदि std::map इस अर्थ में सीमित है और मुझे कुछ और उपयोग करना चाहिए।

मैं आपको सुझावों की सराहना करता हूं और अग्रिम में उनके लिए धन्यवाद देता हूं।

+0

तो सवाल क्या है? –

+1

आपको अपने कोड को एचटीएमएल में बदलना नहीं है। इसे 4 वर्ण इंडेंटेशन के साथ ही रखें। –

+0

डेव में: मेरा प्रश्न है: चूंकि फ़ील्ड टेम्पलेट है, मैं std :: मानचित्र को "बता" कैसे सकता हूं कि मान "किसी भी प्रकार का फ़ील्ड" हैं? litb: सुझाव के लिए धन्यवाद! :-) – jbatista

उत्तर

22

अकेले Field एक प्रकार नहीं है, लेकिन एक टेम्पलेट जो प्रकार के एक परिवार उत्पन्न कर सकते हैं, इस तरह के रूप Field<int> और Field<double>। ये सभी फ़ील्ड इस तरह से संबंधित नहीं हैं कि किसी को किसी अन्य तरह से प्राप्त किया गया है। तो आपको इन सभी जेनरेट किए गए प्रकारों के बीच कुछ संबंध स्थापित करना होगा।

class FieldBase { }; 

template <typename T> 
class Field : public FieldBase { 
    private: 
    T value; 
    DataType<T> type; 
}; 
class Row { 
    private: 
    std::map<unsigned long,FieldBase*> column; 
}; 

और कोड में कि कच्चे सूचक के बजाय स्मार्ट सूचक का उपयोग करें: एक तरह से एक आम गैर टेम्पलेट आधार वर्ग का प्रयोग है। वैसे भी, अब समस्या यह है कि टाइप-सूचना खो जाती है - चाहे आप Field<double> या Field<int> पर इंगित करें, अब और ज्ञात नहीं है और केवल तमाम द्वारा सेट किए गए आधार में किसी प्रकार का प्रकार-ध्वज रखकर पता लगाया जा सकता है व्युत्पन्न वर्ग - या

dynamic_cast<Field<int>*>(field) != 0 

का उपयोग करके आरटीटीआई पूछकर लेकिन यह बदसूरत है। विशेष रूप से क्योंकि आप जो चाहते हैं वह एक मूल्य अर्थपूर्ण है। मैं आप अपनी पंक्ति की प्रतिलिपि बनाने में सक्षम होना चाहता हूं, और यह इसमें सभी फ़ील्ड कॉपी करेगा। और जब आप डबल को संग्रहीत करते हैं तो आप दो बार प्राप्त करना चाहते हैं - आरटीटीआई का उपयोग पहले व्युत्पन्न प्रकार के लिए अपना रास्ता हैक करने के लिए।

ऐसा करने का एक तरीका एक भेदभाव संघ का उपयोग करना है। यह मूल रूप से कुछ मनमाना प्रकारों के लिए एक संघ है और इसके अलावा एक प्रकार-ध्वज, जो स्टोर करता है कि वर्तमान में उस क्षेत्र में कौन सा मूल्य संग्रहीत किया जाता है (जैसे कि एक डबल, int, ...)। उदाहरण के लिए:

template <typename T> 
class Field { 
    private: 
    T value; 
    DataType<T> type; 
}; 
class Row { 
    private: 
    std::map<unsigned long, 
      boost::variant< Field<int>, Field<double> > > 
     column; 
}; 

बूस्ट :: संस्करण आपके लिए सभी काम करता है। आप सही ओवरलोड का उपयोग करके इसे एक मजेदार बनाने के लिए विज़िट का उपयोग कर सकते हैं।इसके manual

1
  1. आपको वहां एक त्रुटि मिली है: आपको फ़ील्ड में सदस्य "मूल्य" करना होगा (शायद एक "प्रकार" होना चाहिए)।
  2. कृपया नक्शा के मूल्य में कच्चे पॉइंटर्स न रखें। boost::shared_ptr का प्रयोग करें।
  3. इसके अलावा, आपके पास ऐसी कक्षाएं लिखने का एक अच्छा कारण होना चाहिए जहां बहुत सारे डीबी/टेबल हैंडलिंग कोड हैं जो आप पहले से ही उपयोग कर सकते हैं। इसलिए, यदि यह लागू है, तो मौजूदा कुछ का उपयोग करने पर विचार करें और अपना खुद का टेबल हैंडलिंग कोड नहीं लिखना।

अब, अपने प्रश्न :), फील्ड <> कक्षाएं एक आम आधार वर्ग कि सभी डेटा प्रकार के द्वारा साझा किया गया है से विरासत सकता है जवाब देने के लिए। इस तरह आपके कॉलम मानचित्र जैसे कंटेनर पॉइंटर्स रख सकते हैं (साझा पॉइंटर्स) टेम्पलेट क्लास के इंस्टेंट किए गए व्युत्पन्न ऑब्जेक्ट्स के लिए।

+0

1. क्षमा करें आप सही हैं, मेरा मतलब था: टी avalue; डेटाटाइप एटइप; 2. मैं बूस्ट लाइब्रेरी से परिचित नहीं हूं (मुझे लगता है कि आप यही बात कर रहे हैं), लेकिन मैं इसे देख लूंगा, धन्यवाद। 3. क्या आप कृपया एक या दो सुझावों को इंगित कर सकते हैं जिन्हें मैं देख सकता हूं? – jbatista

0

Row< int, float, int>Row<int, std::string> से वास्तव में अलग है। स्पष्ट रूप से, Row<int,float,int>.field<0>Field<int> होना चाहिए जबकि Row<int,float,int>.field<1>Field<float> होना चाहिए। और Row<int,float,int>.field<3> एक कंपाइलर त्रुटि है।

ऐसा करने का सबसे आसान तरीका बूस्ट का उपयोग कर रहा है। लोकी द्वारा पूरी तरह से खुफिया जानकारी का नेतृत्व किया गया था (Modern C++ Design, by Andrei Alexandrescu देखें) लेकिन Boost अधिक आधुनिक और बेहतर समर्थित है।

आम तौर पर, आप खेतों में पुन: सक्रिय नहीं होंगे - प्रत्येक फ़ील्ड का अपना प्रकार होता है। लेकिन आप में से, आपको वास्तव में FieldBase की आवश्यकता होगी। यदि आपको ऐसे इंटरफ़ेस की आवश्यकता है, तो शायद boost::array<FieldBase, N> (यानी Row<int,float,int> में boost::array<FieldBase, 3>) के रूप में आंतरिक रूप से फ़ील्ड को स्टोर करना संभव है। आपको dynamic_cast को FieldBase* की आवश्यकता नहीं होनी चाहिए। यह एक रनटाइम टेस्ट है, और आप संकलन समय पर प्रत्येक Field<T> के सटीक T को हमेशा जानते हैं।