2012-12-06 20 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

1つの理由は、ペアの2つの要素が異なるタイプである可能性があることです。これは反復子モデルには適合しません。

同じことが繰り返されるタプルの場合、イテレータはおそらくもっと魅力的です。

固定長の均質な容器コンテナが必要な場合は、std::array<T, n>を使用できます。

+0

stdはstd :: pair std :: equal_rangeを持っています – QuentinUK

+0

@QuentinUKあなたのコメントは、それが何をしているのか分からない人には役に立ちません。 – Andrew

+0

私はもっと長い説明をしましたが、コメントに許されている文字の数に制限はありません。さらなる情報については、少なくともGoogleができます。 – QuentinUK

2

std::pairの目的は、従来のコンテナではなく、2つの潜在的に異種のオブジェクトを1つのものとして扱うタプルとして機能することです。

さらに、ペアの両方の部分に直接アクセスできるため、ペアになった型が同じでない可能性があるため、イテレータは意味がありません。

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 
関連する問題