2013-05-08 8 views
11

मेरे पास एक कस्टम कंटेनर है जिसे मैं कई वर्षों तक बिना किसी समस्या के उपयोग कर रहा हूं। हाल ही में मुझे पता चला कि अगर मैं अपने कंटेनर के लिए इटरेटर को परिभाषित करता हूं, तो मैं <algorithm> में परिभाषित सभी एल्गोरिदम का प्रभावी ढंग से उपयोग कर सकता हूं। इतना ही नहीं, ऐसा लगता है कि thrust library (मूल रूप से एनवीडिया जीपीयू के लिए एसटीएल का सीयूडीए संस्करण) लगता है कि भारी मात्रा में इटरेटर का उपयोग करता है और मुझे आशा है कि उनका उपयोग करके मैं उस लाइब्रेरी का भी उपयोग कर पाऊंगा।कस्टम कंटेनर के लिए एसटीएल-संगत इटरेटर

वैसे भी, क्योंकि यह मेरा खुद का पुनरावर्तक लिखने की मेरी पहली कोशिश है, मैंने सोचा कि मैं यहां जो सहायता करता हूं उसे आगे बढ़ाने के लिए पूछता हूं और सुनिश्चित करता हूं कि मैं जो कर रहा हूं वह सही है। इसलिए, मैंने एक छोटी सी सरणी कक्षा लिखी जो iterator और const_iterator कक्षाओं दोनों का समर्थन करता है। मैंने अपनी कक्षा को विभिन्न एसटीएल एल्गोरिदम के समूह के साथ भाग लिया और सभी ठीक काम करने लगते हैं लेकिन इसका मतलब यह नहीं है कि मुझे सब कुछ ठीक मिला है! विशेष रूप से, क्या कोई ऑपरेटर है जिसे मैं अपने इटरेटर के लिए याद करता हूं? क्या मैंने अतिरिक्त अनावश्यक लोगों को परिभाषित किया है? इसके अलावा, चूंकि iterator और const_iterator के समान दिखते हैं, क्या डुप्लिकेशन को रोकने का कोई तरीका है? http://ideone.com/7YdiQY

#include <cstddef> 
#include <iostream> 
#include <iterator> 
#include <algorithm> 

template<typename T> 
class my_array{ 
    T* data_; 
    std::size_t size_; 

public: 

    // --------------------------------- 
    // Forward declaration 
    // --------------------------------- 
    class const_iterator; 

    // --------------------------------- 
    // iterator class 
    // --------------------------------- 
    class iterator: public std::iterator<std::random_access_iterator_tag, T> 
    { 
    public: 
     iterator(): p_(NULL) {} 
     iterator(T* p): p_(p) {} 
     iterator(const iterator& other): p_(other.p_) {} 
     const iterator& operator=(const iterator& other) {p_ = other.p_; return other;} 

     iterator& operator++() {p_++; return *this;} // prefix++ 
     iterator operator++(int) {iterator tmp(*this); ++(*this); return tmp;} // postfix++ 
     iterator& operator--() {p_--; return *this;} // prefix-- 
     iterator operator--(int) {iterator tmp(*this); --(*this); return tmp;} // postfix-- 

     void  operator+=(const std::size_t& n) {p_ += n;} 
     void  operator+=(const iterator& other) {p_ += other.p_;} 
     iterator operator+ (const std::size_t& n) {iterator tmp(*this); tmp += n; return tmp;} 
     iterator operator+ (const iterator& other) {iterator tmp(*this); tmp += other; return tmp;} 

     void  operator-=(const std::size_t& n) {p_ -= n;} 
     void  operator-=(const iterator& other) {p_ -= other.p_;} 
     iterator operator- (const std::size_t& n) {iterator tmp(*this); tmp -= n; return tmp;} 
     std::size_t operator- (const iterator& other) {return p_ - other.p_;} 

     bool operator< (const iterator& other) {return (p_-other.p_)< 0;} 
     bool operator<=(const iterator& other) {return (p_-other.p_)<=0;} 
     bool operator> (const iterator& other) {return (p_-other.p_)> 0;} 
     bool operator>=(const iterator& other) {return (p_-other.p_)>=0;} 
     bool operator==(const iterator& other) {return p_ == other.p_; } 
     bool operator!=(const iterator& other) {return p_ != other.p_; } 

     T& operator[](const int& n) {return *(p_+n);} 
     T& operator*() {return *p_;} 
     T* operator->(){return p_;} 

    private: 
     T* p_; 

     friend class const_iterator; 
    }; 

    // --------------------------------- 
    // const_iterator class 
    // --------------------------------- 
    class const_iterator: public std::iterator<std::random_access_iterator_tag, T> 
    { 
    public: 
     const_iterator(): p_(NULL) {} 
     const_iterator(const T* p): p_(p) {} 
     const_iterator(const iterator& other): p_(other.p_) {} 
     const_iterator(const const_iterator& other): p_(other.p_) {} 
     const const_iterator& operator=(const const_iterator& other) {p_ = other.p_; return other;} 
     const const_iterator& operator=(const iterator& other) {p_ = other.p_; return other;} 

     const_iterator& operator++() {p_++; return *this;} // prefix++ 
     const_iterator operator++(int) {const_iterator tmp(*this); ++(*this); return tmp;} // postfix++ 
     const_iterator& operator--() {p_--; return *this;} // prefix-- 
     const_iterator operator--(int) {const_iterator tmp(*this); --(*this); return tmp;} // postfix-- 

     void   operator+=(const std::size_t& n)    {p_ += n;} 
     void   operator+=(const const_iterator& other)  {p_ += other.p_;} 
     const_iterator operator+ (const std::size_t& n)  const {const_iterator tmp(*this); tmp += n; return tmp;} 
     const_iterator operator+ (const const_iterator& other) const {const_iterator tmp(*this); tmp += other; return tmp;} 

     void   operator-=(const std::size_t& n)    {p_ -= n;} 
     void   operator-=(const const_iterator& other)  {p_ -= other.p_;} 
     const_iterator operator- (const std::size_t& n)  const {const_iterator tmp(*this); tmp -= n; return tmp;} 
     std::size_t operator- (const const_iterator& other) const {return p_ - other.p_;} 

     bool operator< (const const_iterator& other) const {return (p_-other.p_)< 0;} 
     bool operator<=(const const_iterator& other) const {return (p_-other.p_)<=0;} 
     bool operator> (const const_iterator& other) const {return (p_-other.p_)> 0;} 
     bool operator>=(const const_iterator& other) const {return (p_-other.p_)>=0;} 
     bool operator==(const const_iterator& other) const {return p_ == other.p_; } 
     bool operator!=(const const_iterator& other) const {return p_ != other.p_; } 

     const T& operator[](const int& n) const {return *(p_+n);} 
     const T& operator*() const {return *p_;} 
     const T* operator->() const {return p_;} 

    private: 
     const T* p_; 
    }; 

    my_array() 
     : data_(NULL), size_(0) 
    {} 
    my_array(std::size_t size) 
     : data_(new T[size]), size_(size) 
    {} 
    my_array(const my_array<T>& other){ 
     size_ = other.size_; 
     data_ = new T[size_]; 
     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = other.data_[i]; 
    } 
    my_array(const const_iterator& first, const const_iterator& last){ 
     size_ = last - first; 
     data_ = new T[size_]; 

     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = first[i]; 
    } 

    ~my_array(){ 
     delete [] data_; 
    } 
    const my_array<T>& operator=(const my_array<T>& other){ 
     size_ = other.size_; 
     data_ = new T[size_]; 
     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = other.data_[i]; 
     return other; 
    } 
    const T& operator[](std::size_t idx) const {return data_[idx];} 
    T& operator[](std::size_t& idx) {return data_[idx];} 
    std::size_t size(){return size_;} 

    iterator begin(){ return iterator(data_); } 
    iterator end() { return iterator(data_+size_); } 
    const_iterator begin() const{ return const_iterator(data_); } 
    const_iterator end() const { return const_iterator(data_+size_);} 
}; 

template<typename T> 
void print(T t) { 
    std::cout << t << std::endl; 
} 

int main(){ 

    // works! 
    int list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10}; 
    my_array<int> a(list, list+sizeof(list)/sizeof(int)); 

    // works! 
    for (my_array<int>::const_iterator it = a.begin(), end = a.end(); 
     it != end; ++it) 
     std::cout << ' ' << *it; 
    std::cout << std::endl; 

    // works! 
    std::for_each(a.begin(), a.end(), print<int>); 
    std::cout << std::endl; 

    // works! 
    my_array<int> b(a.size()); 
    std::copy(a.begin(), a.end(), b.begin()); 

    // works! 
    my_array<int>::iterator end = std::remove(a.begin(), a.end(), 5); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    std::random_shuffle(a.begin(), end); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl; 

    // works! 
    std::sort(a.begin(), end); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    if (!std::binary_search(a.begin(), a.end(), 5)) 
     std::cout << "Removed!" << std::endl; 

    return 0; 
} 
+8

मुझे संदेह है कि आप चाहते हैं कि http://codereview.stackexchange.com/ यदि आप मानक लाइब्रेरी संगत इटरेटर्स के लिए आवश्यकताओं की सूची (मानक से अधिक पठनीय) चाहते हैं, तो आप [यहां] शुरू कर सकते हैं (http: // en। cppreference.com/w/cpp/concept/RandomAccessIterator)। – BoBTFish

+0

@BoBTFish अगर मैं अधिक लोगों को वही सोचता हूं तो मैं माइग्रेट कर सकता हूं। मैंने लोगों को ऐसा किया है लेकिन मुझे यकीन नहीं है कि कैसे ... – GradGuy

+0

आप 'cbegin' और' cend' भी जोड़ने पर विचार करना चाहेंगे। – BoBTFish

उत्तर

3

boost iterator एक रूपरेखा एसटीएल अनुरूप iterators बनाने के लिए साथ-साथ मौजूदा अनुकूल करने के लिए प्रदान करता है:

मैं सुझाव और सुधार :)

लाइव उदाहरण के लिए खुला रहा हूँ।

यह आपको कार्यक्षमता पर ध्यान केंद्रित करने और आपके लिए आवश्यक सभी आवश्यक गुणों, टाइपपीफ उत्पन्न करने की अनुमति देता है।

iterator और const_iterator बिना कोड-डुप्लिकेशंस के निर्माण के साथ-साथ सपोर्ट भी समर्थित है।

1

बूस्ट iterator_adaptor आपके कोड को बहुत सरल बना सकता है। documentation उदा। एक लिंक्ड सूची इटरेटर

template <class Value> 
class node_iter 
    : public boost::iterator_adaptor< 
     node_iter<Value>    // Derived 
     , Value*       // Base 
     , boost::use_default    // Value 
     , boost::forward_traversal_tag // CategoryOrTraversal 
    > 
{ 
private: 
    struct enabler {}; // a private type avoids misuse 

public: 
    node_iter() 
     : node_iter::iterator_adaptor_(0) {} 

    explicit node_iter(Value* p) 
     : node_iter::iterator_adaptor_(p) {} 

    template <class OtherValue> 
    node_iter(
     node_iter<OtherValue> const& other 
     , typename boost::enable_if< 
      boost::is_convertible<OtherValue*,Value*> 
      , enabler 
     >::type = enabler() 
    ) 
     : node_iter::iterator_adaptor_(other.base()) {} 

private: 
    friend class boost::iterator_core_access; 
    void increment() { this->base_reference() = this->base()->next(); } 
}; 

ध्यान दें कि उदाहरण के केवल एक डिफ़ॉल्ट निर्माता, एक निर्माता एक नोड सूचक, एक सामान्यीकृत प्रतिलिपि निर्माता है कि केवल तत्व है कि एक नोड सूचक में बदला जा सकता स्वीकार करता लेने प्रदान करता है, और एक के लिए इस उदाहरण वृद्धि समारोह वृद्धि कार्य एक कार्यान्वयन विवरण है जिसे operator++() और operator++(int) दोनों द्वारा साझा किया जाता है।

अन्य सभी बॉयलर प्लेट स्वचालित रूप से boost::iterator_adaptor से प्राप्त करके उत्पन्न की जा रही हैं। इसमें सभी नेस्टेड typedef शामिल हैं जो आप std::iterator से प्राप्त करने के साथ-साथ सभी अधिभारित ऑपरेटरों (++, *, ->, ==,! =, अग्रिम) और किसी और चीज को पूरी तरह से मानक अनुरूप बनाने के लिए प्राप्त कर सकते हैं इटरेटर।

Value const* पास करके और typedef का उपयोग करके आप const_iterator को परिभाषित कर सकते हैं जो उचित संशोधनों के साथ आपके सभी कोड का पुन: उपयोग करता है। उदाहरण का अध्ययन अब आपको सड़क से काफी बचाएगा।

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