19

なぜstd::pairイテレータがないのですか?

std::pairiteratorconst_iterator同様にbegin()とを提供する必要がありますend()-ちょうど彼らの2人のメンバーのために。

vectorまたはのような反復可能を期待するテンプレート化された関数にそれらを渡すことができるので、それは便利だと思いますset

これには欠点がありますか?

4

4 に答える 4

27

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

同じことがタプルにも当てはまります。イテレータを使用する方がおそらくさらに魅力的です。

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

于 2012-12-06T17:55:31.683 に答える
2

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

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

于 2012-12-06T17:57:55.477 に答える
2

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目的ではありません。コンテナではありません。

于 2012-12-06T18:46:12.310 に答える
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
于 2016-12-02T13:14:08.993 に答える