2012-12-06 21 views
13

std::pair क्यों नहीं है?std :: pair में iterators क्यों नहीं है?

std::pairiterator और const_iterator के साथ-साथ begin() और end() प्रदान करना चाहिए - सिर्फ अपने दो सदस्यों के लिए।

मुझे लगता है कि यह उपयोगी होगा क्योंकि तब हम उन्हें टेम्पलेट किए गए कार्यों में पारित कर सकते हैं, जो vector या set जैसे पुनरावृत्तियों की अपेक्षा करते हैं।

क्या इसके लिए कोई डाउनसाइड्स हैं?

+10

'std :: pair '। Iterators केवल सजातीय कंटेनर पर काम करते हैं। –

+0

हालांकि 'std :: pair' कभी-कभी किसी श्रेणी के रूप में उपयोग किया जाता है, इसके बारे में कुछ भी आवश्यक नहीं है या यहां तक ​​कि इस तरह के उपयोग को भी प्रोत्साहित करता है - इसलिए इसके लिए विशेषज्ञता बहुत अच्छी नहीं होगी। सी ++ 11 के शुरुआती मसौदे में वास्तव में यह एक बिंदु पर था। Http://stackoverflow.com/questions/6167598/why-was-pair-range-access-removed-from-c11 –

+2

देखें यदि आप अपने आप को इस तरह के टेम्पलेट किए गए कार्यों में अपनी ऑब्जेक्ट पास करना चाहते हैं तो आपको शायद 'std: : सरणी '' std :: pair 'के बजाय' '। – leftaroundabout

उत्तर

22

एक कारण यह है कि एक जोड़ी के दो तत्व विभिन्न प्रकार के हो सकते हैं। यह इटरेटर मॉडल के साथ फिट नहीं है।

वही टुपल्स के लिए जाता है, जहां इटरेटर शायद अधिक आकर्षक होते हैं।

यदि आपको एक निश्चित लंबाई के समरूप कंटेनर की आवश्यकता है, तो आप std::array<T, n> का उपयोग कर सकते हैं।

+0

std में std :: pair std :: equal_range – QuentinUK

+0

@QuentinUK आपकी टिप्पणी उन लोगों के लिए उपयोगी नहीं है जो यह नहीं जानते कि यह क्या करता है। – Andrew

+0

मैंने एक लंबा स्पष्टीकरण दिया होगा लेकिन टिप्पणी में अनुमत वर्णों की सीमित संख्या में यह संभव नहीं है। अधिक जानकारी के लिए कम से कम Google सकता है। – QuentinUK

2

std::pair का उद्देश्य पारंपरिक कंटेनर नहीं है बल्कि एक ट्यूपल के रूप में कार्य करने के लिए है जो दो संभावित विषम वस्तुओं को एक के रूप में माना जा सकता है।

इसके अतिरिक्त, क्योंकि आपके पास जोड़ी के दोनों हिस्सों तक सीधी पहुंच है, और क्योंकि जोड़े गए प्रकार समान नहीं हो सकते हैं, एक इटरेटर को कोई समझ नहीं आता है।

1

मुझे नहीं लगता कि इसके अलावा कोई विशेष नकारात्मक पक्ष है, यह केवल pair<T,T> के लिए काम करता है, pair<T,U> नहीं।

#include <utility> 
#include <iterator> 
#include <vector> 
#include <iostream> 

namespace itpair { 
    template <typename T> 
    struct pair_iterator : std::iterator<std::forward_iterator_tag, T> { 
     std::pair<T,T> *container; 
     int idx; 
     pair_iterator(std::pair<T,T> *container, int idx) : container(container), idx(idx) {} 
     T &operator*() const { 
      return idx ? container->second : container->first; 
     } 
     T *operator->() const { 
      return &*this; 
     } 
     friend pair_iterator &operator++(pair_iterator &self) { 
      self.idx += 1; 
      return self; 
     } 
     friend pair_iterator operator++(pair_iterator &self, int) { 
      pair_iterator result = self; 
      ++self; 
      return result; 
     } 
     friend bool operator==(const pair_iterator &self, const pair_iterator &other) { 
      return self.container == other.container && self.idx == other.idx; 
     } 
     friend bool operator!=(const pair_iterator &self, const pair_iterator &other) { 
      return !(self == other); 
     } 
    }; 

    template <typename T> 
    pair_iterator<T> begin(std::pair<T,T> &p) { 
     return pair_iterator<T>(&p, 0); 
    } 
    template <typename T> 
    pair_iterator<T> end(std::pair<T,T> &p) { 
     return pair_iterator<T>(&p, 2); 
    } 
} 

int main() { 
    std::pair<int,int> p = std::make_pair(1, 2); 
    using namespace itpair; 
    std::vector<int> v(begin(p), end(p)); 
    std::cout << v[0] << " " << v[1] << "\n"; 
} 
बेशक

आप एक const_iterator भी चाहते हैं, और अगले आप इसे यादृच्छिक अभिगम (जो और अधिक ऑपरेटरों का मतलब है) होने के लिए चाहते हो जाएगा।

जैसा कि सभी कहते हैं, हालांकि, वास्तव में यह नहीं है कि pair है। यह सिर्फ एक कंटेनर नहीं है।

0

मैं इस समाधान के साथ आया था। बहुत "सेक्सी" नहीं है, लेकिन इसे काम करना चाहिए:

#include <type_traits> 
#include <iterator> 
#include <utility> 

#include <boost/optional.hpp> 

namespace pair_iterator { 

template <class A, class B, class Pair> 
class PairIterator { 
public: 
    using iterator_category = std::random_access_iterator_tag; 
    using value_type = std::common_type_t<A, B>; 
    using difference_type = std::ptrdiff_t; 
    using pointer = std::add_pointer_t<value_type>; 
    using reference = std::add_lvalue_reference_t<value_type>; 
    using const_reference = std::add_lvalue_reference_t<const value_type>; 
private: 
    boost::optional<Pair &> pair = {}; 
    difference_type index = 2; 
public: 
    PairIterator(
     const boost::optional<Pair &> &pair = {}, 
     difference_type index = 2 
    ) : pair(pair), index(index) {} 

    // Iterator 

    PairIterator(PairIterator&&) = default; 
    PairIterator(const PairIterator&) = default; 
    PairIterator &operator =(PairIterator&&) = default; 
    PairIterator &operator =(const PairIterator&) = default; 
    ~PairIterator() = default; 

    void swap(PairIterator &other) { 
     std::swap(pair, other.pair); 
     std::swap(index, other.index); 
    } 

    reference operator *() { 
     return index == 0 ? pair->first : pair->second; 
    } 

    const_reference operator *() const { 
     return index == 0 ? pair->first : pair->second; 
    } 

    PairIterator &operator ++() { 
     ++index; 
     return *this; 
    } 

    // InputIterator 

    bool operator ==(const PairIterator &other) const { 
     return index == other.index; 
    } 

    bool operator !=(const PairIterator &other) const { 
     return index != other.index; 
    } 

    PairIterator operator ++(int) const { 
     return { pair, index+1 }; 
    } 

    // ForwardIterator 

    // BidirectionalIterator 

    PairIterator &operator --() { 
     --index; 
     return *this; 
    } 

    PairIterator operator --(int) const { 
     return { pair, index-1 }; 
    } 

    // RandomAccessIterator 

    PairIterator &operator +=(difference_type n) { 
     index += n; 
     return *this; 
    } 

    PairIterator operator +(difference_type n) const { 
     return { pair, index+n }; 
    } 

    PairIterator &operator -=(difference_type n) { 
     index -= n; 
     return *this; 
    } 

    PairIterator operator -(difference_type n) const { 
     return { pair, index-n }; 
    } 

    difference_type operator -(const PairIterator &other) const { 
     return index - other.index; 
    } 

    reference operator [](difference_type n) { 
     return (index+n) == 0 ? pair->first : pair->second; 
    } 

    const_reference operator [](difference_type n) const { 
     return (index+n) == 0 ? pair->first : pair->second; 
    } 

    bool operator <(const PairIterator &other) const { 
     return index < other.index; 
    } 

    bool operator >(const PairIterator &other) const { 
     return index > other.index; 
    } 

    bool operator <=(const PairIterator &other) const { 
     return index <= other.index; 
    } 

    bool operator >=(const PairIterator &other) const { 
     return index >= other.index; 
    } 
}; 

template <class A, class B> 
auto begin(std::pair<A, B> &pair) -> 
PairIterator<A, B, std::pair<A, B>> { 
    return { pair, 0 }; 
} 

template <class A, class B> 
auto end(std::pair<A, B> &pair) -> 
PairIterator<A, B, std::pair<A, B>> { 
    return { pair, 2 }; 
} 

template <class A, class B> 
auto begin(const std::pair<A, B> &pair) -> 
PairIterator<const A, const B, const std::pair<A, B>> { 
    return { pair, 0 }; 
} 

template <class A, class B> 
auto end(const std::pair<A, B> &pair) -> 
PairIterator<const A, const B, const std::pair<A, B>> { 
    return { pair, 2 }; 
} 

} // namespace pair_iterator 

namespace std { 

using pair_iterator::begin; 
using pair_iterator::end; 

} // namespace std 
संबंधित मुद्दे