2012-12-06 6 views
13

std::pair에는 반복자가 있습니까? 왜 std :: pair에는 반복자가 없습니까?

std::pair

iteratorconst_iterator뿐만 아니라 begin()end()을 제공해야한다 - 단지 자신의 두 멤버.

vector 또는 set과 같이 iterables를 예상하는 템플릿 기능에 전달할 수 있기 때문에 유용하다고 생각합니다.

여기에 단점이 있습니까?

+10

'std :: pair '. 반복자는 동종 컨테이너에서만 작동합니다. –

+0

'std :: pair '가 때로는 범위로 사용되지만, 그것에 관해서는 아무것도 사용하거나 권장하지 않습니다. 그래서 그렇게 전문적이지는 않을 것입니다. C++ 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를 가지고 있습니다. ForwardIt, ForwardIt> std :: equal_range – QuentinUK

+0

@QuentinUK 여러분의 의견은 그것이 무엇을하는지 모르는 사람들에게는 도움이되지 않습니다. – Andrew

+0

나는 더 긴 설명을 넣었을 지 모르지만 주석에 허용 된 제한된 수의 문자로는 가능하지 않습니다. 하나 이상의 구글에 대한 자세한 내용은. – 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 
관련 문제