2012-12-06 144 views
13

爲什麼std::pair沒有迭代器?爲什麼std :: pair沒有迭代器?

std::pair應提供iteratorconst_iterator以及begin()end() - 只爲他們的兩個成員。

我認爲它會很有用,因爲那樣我們就可以將它們傳遞到期望迭代的模板函數中,如vectorset

這是否有任何缺點?

+10

'std :: pair '。迭代器只能在同質容器上工作。 –

+0

雖然'std :: pair'有時被用作範圍,但它並不需要甚至鼓勵使用,所以專業化並不會太大。早期的C++ 11草案實際上曾經有過這種觀點。見http://stackoverflow.com/questions/6167598/why-was-pair-range-access-removed-from-c11 –

+2

如果你發現自己想要將你的對象傳遞給這樣的模板函數,那麼你應該使用'std: :array '而不是'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 
相關問題