Почему в std :: pair нет итераторов?

Почему не std::pair есть итераторы?

std::pair должен обеспечить iterator а также const_iterator так же как begin() а также end() — только для их двух членов.

Я думаю, что это было бы полезно, потому что тогда мы могли бы передать их в шаблонные функции, которые ожидают итераций, таких как vector или же set,

Есть ли минусы в этом?

13

Решение

Одна из причин заключается в том, что два элемента пары могут быть разных типов. Это не соответствует модели итератора.

То же самое касается кортежей, где наличие итераторов, возможно, будет еще более привлекательным.

Если вам нужен недорогой гомогенный контейнер фиксированной длины, вы можете использовать std::array<T, n>,

22

Другие решения

Цель std::pair не должен быть традиционным контейнером, а должен служить кортежем, который позволяет обрабатывать два потенциально гетерогенных объекта как один.

Кроме того, поскольку у вас есть прямой доступ к обеим частям пары, а типы пар не могут быть одинаковыми, итератор не имеет смысла.

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 для. Это просто не контейнер.

1

Я придумал это решение. Не очень «сексуально», но должно работать

#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
0
По вопросам рекламы [email protected]