2012-12-06 186 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 
相关问题