2009-09-06 21 views
6

मैं सी में एक "विरल" वेक्टर वर्ग बनाने के लिए कोशिश कर रहा हूँ ++, इसलिए जैसे के लिए:ओवरलोडिंग ऑपरेटर [] एक विरल वेक्टर

template<typename V, V Default> 
class SparseVector { 
    ... 
} 

आंतरिक रूप से, यह एक std::map<int, V> द्वारा प्रतिनिधित्व किया जाएगा (जहां V है संग्रहीत मूल्य का प्रकार)। यदि मानचित्र में कोई तत्व मौजूद नहीं है, तो हम दिखाएंगे कि यह टेम्पलेट तर्क से Default मान के बराबर है।

हालांकि, मुझे सबस्क्रिप्ट ऑपरेटर, [] अधिभार में परेशानी हो रही है। मुझे [] ऑपरेटर अधिभारित करना होगा, क्योंकि मैं इस वर्ग से ऑब्जेक्ट को बूस्ट फ़ंक्शन में पास कर रहा हूं जो [] को सही तरीके से काम करने की अपेक्षा करता है।

const संस्करण काफी आसान है: जांच करें कि सूचकांक मानचित्र में है या नहीं, तो इसके मूल्य को वापस करें, या Default अन्यथा।

हालांकि, गैर-कॉन्स संस्करण के लिए मुझे संदर्भ वापस करने की आवश्यकता है, और यही वह जगह है जहां मैं परेशानी में भाग लेता हूं। यदि मान केवल पढ़ रहा है, तो मुझे मानचित्र में कुछ भी जोड़ने की आवश्यकता नहीं है (न ही चाहते हैं); लेकिन अगर यह लिखा गया है, तो मुझे संभवतः मानचित्र में एक नई प्रविष्टि डालने की आवश्यकता है। समस्या यह है कि ओवरलोडेड [] यह नहीं जानता कि कोई मान या लिखा पढ़ा गया है या नहीं। यह केवल एक संदर्भ देता है।

क्या इस समस्या को हल करने का कोई तरीका है? या शायद इसके आसपास काम करने के लिए?

+2

boost :: mapped_vector <> कुछ ऐसा करना चाहिए - आप इसे विचारों के लिए पढ़ सकते हैं (या शायद इसका उपयोग कर सकते हैं)। –

+0

यह मेरे डिफ़ॉल्ट मानों का समर्थन नहीं करता है, और साथ ही, मैं इसे दो-आयामी मैट्रिक्स के लिए करने जा रहा था, इसलिए इसका उपयोग सीधे प्रश्न से बाहर है। लेकिन अभी भी एक उपयोगी संदर्भ! – Thomas

उत्तर

13

कुछ बहुत ही सरल चाल हो सकती है, लेकिन अन्यथा मुझे लगता है कि operator[] केवल कुछ जो वी से सौंपा जा सकता है (और वी करने के लिए परिवर्तित) वापस जाने के लिए है, जरूरी नहीं कि एक वी &। तो मुझे लगता है कि आपको किसी ऑब्जेक्ट को ओवरलोडेड operator=(const V&) के साथ वापस करने की आवश्यकता है, जो आपके स्पैस कंटेनर में प्रविष्टि बनाता है।

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

+0

यह एकमात्र समाधान है। दूसरी ओर, प्रॉक्सी ऑब्जेक्ट्स या तो सही नहीं हैं - उदाहरण के लिए, यदि 'वी' में कोई ओवरलोडेड रूपांतरण ऑपरेटर था, तो प्रॉक्सी उन्हें बिना किसी प्रचार के सक्षम नहीं कर पाएगी। –

+0

आह ने अभी बूस्ट वैक्टर का परीक्षण किया। ऐसा लगता है कि वे इस तरह से व्यवहार करते हैं। दिलचस्प। –

+0

(और 'वेक्टर ' या तो एक एसटीएल कंटेनर नहीं है।) – sbi

9

गैर-कॉन्स ऑपरेटर & कार्यान्वयन को संदर्भ न दें, लेकिन एक प्रॉक्सी ऑब्जेक्ट दें। इसके बाद आप प्रॉक्सी ऑब्जेक्ट के असाइनमेंट ऑपरेटर को कार्यान्वित करने के लिए ऑपरेटर [] को एक्सेस एक्सेस से अलग कर सकते हैं।

विचार को चित्रित करने के लिए यहां कुछ कोड स्केच है। यह दृष्टिकोण सुंदर नहीं है, लेकिन ठीक है - यह सी ++ है। सी ++ प्रोग्रामर सौंदर्य प्रतियोगिता में प्रतिस्पर्धा करने में समय बर्बाद नहीं करते हैं (वे या तो मौका नहीं खड़े होंगे)। ;-)

template <typename V, V Default> 
ProxyObject SparseVector::operator[](int i) { 
    // At this point, we don't know whether operator[] was called, so we return 
    // a proxy object and defer the decision until later 
    return ProxyObject<V, Default>(this, i); 
} 

template <typename V, V Default> 
class ProxyObject { 
    ProxyObject(SparseVector<V, Default> *v, int idx); 
    ProxyObject<V, Default> &operator=(const V &v) { 
     // If we get here, we know that operator[] was called to perform a write access, 
     // so we can insert an item in the vector if needed 
    } 

    operator V() { 
     // If we get here, we know that operator[] was called to perform a read access, 
     // so we can simply return the existing object 
    } 
}; 
+0

क्या कोई प्रकार बदलने योग्य है उदाहरण के लिए एक 'कॉन्स int' और 'int' 'दोनों, और जब भी यह गैर-लिखने योग्य आभासी उपयोग कर सकता है तो संकलक पूर्व का चयन कर सकता है? मैं एक प्रॉक्सी ऑब्जेक्ट को उस फ़ील्ड के संदर्भ को वापस लौटना चाहता हूं जो मुख्य ऑब्जेक्ट को लोड किया गया है, और उसके बाद इसके विनाशक क्षेत्र को मुख्य ऑब्जेक्ट पर प्रतिलिपि बनाते हैं यदि यह बदल सकता है, लेकिन मैं यह नहीं समझ सकता कि कैसे केवल पढ़ने के लिए पहुंच पर लिखने के लिए बचने के लिए। – supercat

1

मुझे आश्चर्य है कि यह डिज़ाइन ध्वनि है या नहीं।

यदि आप कोई संदर्भ वापस करना चाहते हैं, तो इसका मतलब है कि कक्षा के ग्राहक संदर्भ में operator[] पर कॉल करने के परिणाम संग्रहीत कर सकते हैं, और किसी भी समय बाद में इसे लिख/लिख सकते हैं। यदि आप किसी संदर्भ को वापस नहीं करते हैं, और/या किसी विशिष्ट अनुक्रमणिका को संबोधित करते समय तत्व को सम्मिलित नहीं करते हैं, तो वे यह कैसे कर सकते हैं? (साथ ही, मुझे यह महसूस हो रहा है कि उस ऑपरेटर को एक संदर्भ वापस करने के लिए मानक को उचित एसटीएल कंटेनर operator[] प्रदान करना आवश्यक है, लेकिन मुझे इसके बारे में निश्चित नहीं है।)

आप अपनी प्रॉक्सी को operator V&() (जो प्रविष्टि बनायेगा और डिफ़ॉल्ट मान असाइन करेगा) देकर इसे रोकने में सक्षम हो सकता है, लेकिन मुझे यकीन नहीं है कि यह कुछ मामलों में एक और लूप होल नहीं खोल पाएगा मैंने अभी तक सोचा नहीं था।

std::map यह समस्या निर्दिष्ट करके यह समस्या हल करती है कि उस ऑपरेटर का गैर-कॉन्स संस्करण हमेशा एक तत्व (और const संस्करण प्रदान नहीं करता) प्रदान करता है।

बेशक, आप हमेशा कह सकते हैं इस एक ऑफ-द-शेल्फ एसटीएल कंटेनर नहीं है, और operator[] सादा संदर्भ उपयोगकर्ताओं स्टोर कर सकते हैं वापस नहीं करता है। और शायद यह ठीक है। मैं बस विचार करता हूँ।

+0

डिज़ाइन की सुदृढ़ता के बारे में: यह सामान्य मामलों में उपयोग किए जाने वाले सामान्य वेक्टर की स्मृति अनुकूलन है - इसलिए इंटरफ़ेस/अनुबंध/दस्तावेज़ीकरण को कवर करना चाहिए। संदर्भों की वैधता के बारे में: यहां तक ​​कि stl iterators हमेशा मान्य नहीं होते हैं। – xtofl

+2

@xtofl: हालांकि, एसटीएल कंटेनर बहुत सावधानी से परिभाषित करते हैं कि कौन से ऑपरेशन कंटेनर के तत्वों के लिए इटरेटर और/या संदर्भों को अमान्य कर सकते हैं। इस कंटेनर को वही करना चाहिए, और उपयोगकर्ताओं को यह सुनिश्चित करना होगा कि कक्षा का उपयोग करने वाले किसी भी टेम्पलेट पैरामीटर के रूप में मांग नहीं करता है कि यह संतुष्ट नहीं हो सकता है। –

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