2009-07-09 12 views
11

में इटरेटर मेरे पास है:"सामान्य" C++

void add_all_msgs(std::deque<Message>::iterator &iter); 

मैं कैसे, कि समारोह "सामान्य" कर सकते हैं तो यह inputiterators किसी भी प्रकार के कर सकते हैं? मुझे वास्तव में परवाह नहीं है कि यह एक डेक, एक वेक्टर या कुछ और है, जब तक कि इटेटरेटर संदेश को पुन: सक्रिय कर रहा हो। - क्या यह सी ++ में सीधे आगे संभव है?

उत्तर

6
template<class InputIterator> 
void add_all_msgs(InputIterator iter); 

उपयोग:

std::deque<Message> deq; 
add_all_msgs(deq.begin()); 
+5

कन्वेंशन संदर्भ के बजाय मानकों को मूल्य से लेना है।इसके अलावा, इटेटरेटर सामान्य रूप से "छोटे" होते हैं, इसके कारण (afaik) कॉलर को अस्थायी रूप से पास करने की अनुमति देना है, जैसे std :: back_inserter से वापसी मान। सी ++ 0x कम से कम दो तरीकों से इस बारे में सोच सकता है। –

+0

हे, या "शुरूआत" से वापसी मूल्य इसके बारे में सोचने के लिए आते हैं। उपर्युक्त "उपयोग" कोड संकलित नहीं करता है: "अस्थायी प्रकार 'blah' प्रकार के गैर-कॉन्स्ट संदर्भ के प्रकार 'blah' के अमान्य प्रारंभिक 'blah'। –

+1

ओपी ने स्पष्ट रूप से कहा: "जब तक इटेटरेटर संदेश पुनरावृत्त कर रहा है"। इस समाधान, और अन्य लोगों ने, इस आवश्यकता को पूरी तरह से अनदेखा कर दिया। –

0
#include <deque> 
#include <vector> 
#include <list> 
#include <string> 
using namespace std; 

template<typename T> 
void add_all_msgs(T &iter) 
{ 

} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::deque<string>::iterator it1; 
    std::vector<string>::iterator it2; 
    std::list<string>::iterator it3; 

    add_all_msgs(it1); 
    add_all_msgs(it2); 
    add_all_msgs(it3); 


    return 0; 
} 
+0

और add_all_msgs को कम से कम एक टेम्पलेट होना चाहिए? Iterators "polymorphic" नहीं है? – nos

+0

@noselasd: अगर आप इसका मतलब रखते हैं तो इटेटरेटर सामान्य बेस क्लास से नहीं निकलते हैं। –

+0

तो वे _are_ polymorphic (स्थिर बतख टाइपिंग के माध्यम से), जावा में कहते हैं कि पॉलिमॉर्फिज्म के बारे में सोचने के तरीके में नहीं। –

12
template <typename Iterator> 
void add_all_messages(Iterator first, Iterator last) 

उपयोग:

vector<message> v; 
add_all_messages(v.begin(), v.end()); 

आप अंत निर्दिष्ट करने की आवश्यकता है, अन्यथा आप को पता नहीं चलेगा जब रोकने के लिए! यह आपको एक कंटेनर के केवल एक सब्रेंज जोड़ने की लचीलापन भी देता है।

+0

खैर, मुझे वास्तव में माना जाता है (एजे के विपरीत) कि इटरेटर को आउटपुट इटरेटर के रूप में उपयोग किया जाता है, इस मामले में, अंतिम इटेटरेटर अनिवार्य है। :- पी –

+0

ओह रुको, ओपी का कहना है कि यह एक इनपुट इटरेटर है। मुद्दा लेना। :- पी –

5

यदि आप संकलक को यह जांचना चाहते हैं कि इटेटरेटर वास्तव में Message ऑब्जेक्ट्स को संदर्भित करता है, तो आप निम्न की तरह एक तकनीक का उपयोग कर सकते हैं।

template <typename InputIterator, typename ValueType> 
struct AddAllMessages { }; 

template <typename InputIterator> 
struct AddAllMessages<InputIterator, Message> { 
    static void execute(const InputIterator &it) { 
    // ... 
    } 
}; 

template <typename InputIterator> 
void add_all_msgs(const InputIterator &it) { 
    AddAllMessages<InputIterator, 
       typename std::iterator_traits<InputIterator>::value_type>::execute(it); 
} 
1

थोड़ा सरल है कि इसके बाद के संस्करण (कि यह लाभ उठाता है मौजूदा पुस्तकालयों):

#include <boost/static_assert.hpp> // or use C++0x static_assert 
#include <boost/type_traits/is_same.hpp> 

template <typename InputIterator> 
void add_all_msgs(InputIterator it) { 
    BOOST_STATIC_ASSERT((boost::is_same< 
     typename std::iterator_traits<InputIterator>::value_type, 
     Message>::value)); 
    // ... 
2

आप अपने add_all_msgs समारोह templatize नहीं करना चाहते हैं, तो आप adobe::any_iterator उपयोग कर सकते हैं:

typedef adobe::any_iterator<Message, std::input_iterator_tag> any_message_iterator; 
void add_all_msgs(any_message_iterator begin, any_message_iterator end); 
+0

निफ्टी। [15chars] –

+0

मैं अब के लिए add_all_msgs templating के साथ जाऊंगा, हालांकि यह वही है जो मैं आदर्श रूप से चाहता था। – nos

+2

टेम्पलेट संस्करण निश्चित रूप से अधिक कुशल है, किसी भी_इटरेटर के साथ आपके पास प्रत्येक ऑपरेशन (यानी अगली स्थिति में जाना, और dereferencing) पर एक वर्चुअल फ़ंक्शन कॉल है, जिसमें इनलाइन फ़ंक्शन कॉल बनाम है। –

1

सी ++ - स्टाइल इटरेटर्स के साथ गतिशील बहुरूपता होना मुश्किल है। operator++(int) मूल्य से लौटाता है, जो afaik अव्यवस्थित है: आपके पास वर्चुअल सदस्य फ़ंक्शन नहीं हो सकता है जो *this को बिना कटाई के मान देता है।

यदि संभव हो, तो मैं टेम्पलेट का उपयोग करने की सलाह देता हूं क्योंकि हर कोई कहता है।

लेकिन यदि आप गतिशील बहुरूपता, उदाहरण के लिए की जरूरत है, क्योंकि आप add_all_msgs के कार्यान्वयन का खुलासा नहीं कर सकते हैं के रूप में एक टेम्पलेट करना होगा, तो मुझे लगता है कि आप जावा होने का नाटक कर सकता है, इस तरह कार्य करें:

struct MessageIterator { 
    virtual Message &get() = 0; 
    virtual void next() = 0; 
    // add more functions if you need more than a Forward Iterator. 
    virtual ~MessageIterator() { }; // Not currently needed, but best be safe 
}; 

// implementation elsewhere. Uses get() and next() instead of * and ++ 
void add_all_msgs(MessageIterator &it); 

template <typename T> 
struct Adaptor : public MessageIterator { 
    typename T::iterator wrapped; 
    Adaptor(typename T::iterator w) : wrapped(w) { } 
    virtual Message &get() { 
     return *wrapped; 
    } 
    virtual void next() { 
     ++wrapped; 
    } 
}; 

int main() { 
    std::deque<Message> v; 
    Adaptor<std::deque<Message> > a(v.begin()); 
    add_all_msgs(a); 
} 

मैंने जांच की है कि यह संकलित है, लेकिन मैंने इसका परीक्षण नहीं किया है और मैंने पहले कभी इस डिज़ाइन का उपयोग नहीं किया है। मैंने कॉन्स-नेस से भी परेशान नहीं किया है - अभ्यास में आप शायद const Message &get() const चाहते हैं। और फिलहाल एडाप्टर को रोकने के बारे में जानने का कोई तरीका नहीं है, लेकिन फिर आपके द्वारा शुरू किया गया कोड न तो करता है, इसलिए मैंने उसे भी अनदेखा कर दिया है। असल में आपको hasNext फ़ंक्शन की आवश्यकता होगी जो कि wrapped की तुलना में कन्स्ट्रक्टर को प्रदान किए गए अंत इटरेटर के विरुद्ध तुलना करेगी।

आप टेम्पलेट फ़ंक्शन और कॉन्स संदर्भों के साथ कुछ करने में सक्षम हो सकते हैं, ताकि ग्राहक को उस ग़लत एडाप्टर प्रकार के बारे में जानना या घोषित न हो।

[संपादित करें: इसके बारे में सोचने के लिए आओ, शायद add_all_msgs फ़ंक्शन टेम्पलेट होना बेहतर है, जो एडाप्टर में अपना पैरामीटर लपेटता है और फिर real_add_all_msgs पर कॉल करता है। यह पूरी तरह से क्लाइंट से एडाप्टर को छुपाता है।]