2009-04-16 19 views
7

पर एक स्थिरांक वेक्टर सदस्य चर मैं एक दसवीं कक्षा, जिसे मैंने यहां का एक टुकड़ा प्रदान में पर्वतमाला:श्रृंखलाबद्ध सी ++ इटरेटर निर्माण समय

class X { 
    public: 
    template <typename Iter> 
    X(Iter begin, Iter end) : mVec(begin, end) {} 

    private: 
    vector<Y> const mVec; 
}; 

मैं अब इस वर्ग के लिए एक नया श्रृंखलाबद्ध निर्माता जोड़ना चाहते हैं, कुछ की तरह:

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(???) { ??? } 

इस तरह के एक निर्माता [begin1, END1) दो सीमाओं तथा [begin2 कड़ी लगाकर जोड़ना होगा, end2) mVec में। चुनौतियों

1 कर रहे हैं) इतना है कि यह मैं सभी संभव हो तो पर अनावश्यक प्रतियां से बचने के लिए चाहते हैं एक्स

2) के अन्य तरीकों में स्थिर माना जाता है मैं, mVec पर स्थिरांक की रक्षा करना चाहते हैं। यही कारण है कि आवेषण लेकर 2 एक समाधान के लिए एक स्थिर विधि है कि एक गैर स्थिरांक अस्थायी निर्माण करती लेकर 1 है, है, और यह देता है, और उसके बाद में सभी मूल्यों

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) 
    : mVec(concatenate(begin1, end1, begin2, end2)) { } 

लिए लेकिन यह है कि प्रतियां श्रृंखलाबद्ध निर्माता को परिभाषित कम से कम एक अतिरिक्त समय, मुझे विश्वास है।

उत्तर

9

अच्छी समस्या। मैं एक विशेष इटरेटर रैपर प्रकार को लागू करने की कोशिश करता हूं जो दो श्रेणियों को एक ही श्रेणी में बदल देता है। की लाइनों में कुछ:

// compacted syntax for brevity... 
template <typename T1, typename T2> 
struct concat_iterator 
{ 
public: 
    typedef std::forward_iterator_tag iterator_category; 
    typedef typename iterator_traits<T1>::value_type value_type; 
    typedef *value_type pointer; 
    typedef &value_type reference; 

    concat_iterator(T1 b1, T1 e1, T2 b2, T2 e2) 
     : seq1(b1), seq1end(e1), seq2(b2), seq2end(e2); 
    iterator& operator++() { 
     if (seq1 != seq1end) ++seq1; 
     else ++seq2; 
     return this; 
    } 
    reference operator*() { 
     if (seq1 != seq1end) return *seq1; 
     else return *seq2; 
    } 
    pointer operator->() { 
     if (seq1 != seq1end) return &(*seq1); 
     else return &(*seq2); 
    } 
    bool operator==(concat_iterator const & rhs) { 
     return seq1==rhs.seq1 && seq1end==rhs.seq2 
      && seq2==rhs.seq2 && seq2end==rhs.seq2end; 
    } 
    bool operator!=(contact_iterator const & rhs) { 
     return !(*this == rhs); 
    } 
private: 
    T1 seq1; 
    T1 seq1end; 
    T2 seq2; 
    T2 seq2end; 
}; 

template <typename T1, typename T2> 
concat_iterator<T1,T2> concat_begin(T1 b1, T1 e1, T2 b2, T2 e2) 
{ 
    return concat_iterator<T1,T2>(b1,e1,b2,e2); 
} 
template <typename T1, typename T2> 
concat_iterator<T1,T2> concat_end(T1 b1, T1 e1, T2 b2, T2 e2) 
{ 
    return concat_iterator<T1,T2>(e1,e1,e2,e2); 
} 

अब आप इस्तेमाल कर सकते हैं:

class X { 
public: 
    template <typename Iter, typename Iter2> 
    X(Iter b1, Iter e1, Iter2 b2, Iter2 e2) 
     : mVec(concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2)) 
    {} 

    private: 
    vector<Y> const mVec; 
}; 

या (मैं सिर्फ इसके बारे में सोचा है) आप अपने निर्माता redeclare की जरूरत नहीं है। अपने कॉलर को सहायक कार्यों का उपयोग करें:

X x(concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2)); 

मैंने कोड की जांच नहीं की है, बस इसे मेरे सिर के ऊपर से टाइप किया है। यह संकलित हो सकता है या यह नहीं कर सका, यह काम कर सकता है या नहीं ... लेकिन आप इसे प्रारंभ बिंदु के रूप में ले सकते हैं।

+0

चतुर समाधान के लिए +1 ... एक पुनरावर्तक जो इटरेटर की दो श्रेणियों को फैलाता है ... अच्छा – veefu

+0

boost :: iterator_facade का उपयोग करके लिखना आसान होगा, लेकिन शायद इस मामले में यह सबसे अच्छा शर्त है। कम से कम, जब तक हमारे पास चाल-समर्थन नहीं होता है। – Macke

+0

concat_end की आवश्यकता को न देखें। आप जनरेटेड इटरेटर की तुलना कर सकते हैं टाइप टी 2 के प्रकार टी 2 के साथ एक बूल उत्पन्न करते हैं। –

2

शायद const ड्रॉप करना सबसे अच्छा होगा (आप वैसे भी इस पर जोर क्यों देंगे?)।

अन्यथा, आपको एक संयोजक इटरेटर बनाना होगा। यह बहुत सारे कोड है, और अधिक के लिए this thread देखें।

+0

मेरे मामले में, उदाहरण के निर्माण के बाद वेक्टर सदस्य चर बदलना नहीं चाहिए। इसे बनाने से कंपाइलर मुझे इसकी गारंटी देने में मदद करता है। – SCFrench

+0

ठीक है, concatenation करने के लिए आवश्यक कोड की मात्रा दी गई है, यदि आपके पास कॉन्स रखें तो आपके कोड में एक बग होगा। – avakar

+0

एससीफ़्रेंच, क्या यह सुरक्षित नहीं है कि एक्स :: एमवीसी के निर्माण के बाद बदल नहीं जाएगा? – veefu

2

आपके दृष्टिकोण के आधार पर सी ++ की सबसे अच्छी या सबसे खराब सुविधाओं में से एक यह है कि काम पूरा करने के लिए आवश्यक होने पर आप इसका दुरुपयोग कर सकते हैं।

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(begin1, end1) { 
    const_cast<vector<Y>&>(mVec).insert(mVec.end(), begin2, end2); 
} 

मैं विवरण में से कुछ गलत हो सकता है, मैं इस संकलन करने की कोशिश नहीं की: इस मामले में, const_cast शिकार है। लेकिन यह आपको विचार देना चाहिए।

+0

मैं एक जटिल इटरेटर रैपर पर काम कर रहा था जो दोनों श्रेणियों को ले जाएगा ... यह बहुत आसान है, भले ही ... const_cast ouch! –

+0

यह वास्तव में अपरिभाषित व्यवहार है। आपको उन ऑब्जेक्ट्स से कॉन्स्ट को नहीं हटाया जाना चाहिए जिन्हें परिभाषित किया गया था। हालांकि, आप कॉन्स्ट रेफरेंस से कॉन्स्ट को गैर-कॉन्स्ट ऑब्जेक्ट से बाध्य कर सकते हैं। – avakar

+1

अपरिभाषित हमेशा अप्रत्याशित नहीं है। जैसा कि मैंने कहा, यह निश्चित रूप से दुरुपयोग है। –

1

आपका स्थिर तरीका आपके संकलक के अनुकूलन के आधार पर जितना बुरा लगता है उतना बुरा नहीं हो सकता है। और सी ++ 0x में, चालक कन्वर्टर्स वर्तमान में होने वाली किसी भी प्रतिलिपि को हटा देंगे।

इस बीच एक रैपर इटरेटर के साथ जाना। थ्रेड अवकर लिंक के रूप में कोड खराब होने की संभावना नहीं है, क्योंकि आपको केवल input iterator को लागू करने की आवश्यकता है।

1

1) मैं एमवीईसी पर कॉन्स को संरक्षित करना चाहता हूं, ताकि इसे एक्स के अन्य तरीकों में निरंतर माना जा सके।

  • यह एक सदस्य चर पर const की एक जिज्ञासु इस्तेमाल होता है। और यह अच्छी डिजाइन की निंदा करता है। परिभाषा के अनुसार, निर्माण एक प्रक्रिया है जिसके लिए वस्तु को बदलने की आवश्यकता होती है।

  • ऑब्जेक्ट को गैर-संशोधित रखने की आपकी आवश्यकता के लिए - उचित encapsulation का उपयोग करें। आपको अपनी कक्षा के ग्राहकों के लिए mVec के आधार पर किसी भी कार्यक्षमता का पर्दाफाश करने के लिए const -member फ़ंक्शंस का उपयोग करना चाहिए।

2) यदि संभव हो तो मैं अनावश्यक प्रतियों से बचना चाहता हूं। यही है, एक समाधान एक स्थैतिक विधि है जो एक रेंज 1 के लिए अस्थायी अस्थायी बनाता है, रेंज 2 को सम्मिलित करता है और इसे वापस करता है, और फिर

पर संयोजक कन्स्ट्रक्टर को परिभाषित करता है, आपको चालक-निर्माणकर्ताओं और आर को देखना चाहिए सामान्य रूप से सामान्य संदर्भ (सी ++ 0x का वादा किया गया लक्ष्य)। इसे article पढ़ें।

+0

मुझे आपकी पहली बुलेट नहीं समझती है। मेरे मामले में, ऑब्जेक्ट बनने के बाद, वेक्टर को असम्बद्ध रहना चाहिए। इसे लागू करने में मदद नहीं करेगा इसे लागू करने में मदद करें? सदस्य चर पर स्थिरांक का एक गैर-उत्सुक उपयोग क्या होगा? – SCFrench

+0

जब मैंने स्थैतिक नहीं था तो मैंने 'const' सदस्य चर का अधिक उपयोग नहीं देखा है। आप जो चाहते हैं वह एक पाठक सदस्य है और जिस तरह से आप चाहते हैं उसे करने के लिए सी ++ में कोई रचना नहीं है। आपकी सबसे अच्छी शर्त const_casts के कारण संशोधन द्वारा यूबी को आविष्कार करने के बजाय कॉन्स्ट एक्सेसर्स का उपयोग करना है। – dirkgently