Вот пример реализации, которая определяет новый тип итератора для предоставления парного представления двух последовательностей.Я пытался сделать его совместимым со стандартами и правильным, но поскольку стандарт C ++ ужасно сложен в своих деталях, я почти уверен, что потерпел неудачу.Я скажу, что этот код, кажется, работает при сборке с clang++
или g++
.
Этот код не рекомендуется для общего использования, поскольку онболее длинный и менее понятный, чем другие ответы, и, возможно, вызывает страшное «неопределенное поведение».
Однако имеет преимущество в постоянных временных и пространственных накладных расходах, поскольку дает представление осуществующие данные, а не фактически создание временного альтернативного представления или вектора перестановки.Наиболее очевидная (для меня) проблема производительности с этим кодом заключается в том, что отдельные элементы двух контейнеров должны быть скопированы во время операции подкачки.Несмотря на несколько попыток, я не нашел способа успешно специализировать std::swap
, чтобы std::sort
или std::random_shuffle
не использовали стандартную реализацию подкачки на основе временных копий.Вполне возможно, что использование справочной системы C ++ 0x rvalue (см. std::move
и ответ Джона Перди) может решить эту проблему.
#ifndef HDR_PAIRED_ITERATOR
#define HDR_PAIRED_ITERATOR
#include <iterator>
/// pair_view mostly looks like a std::pair,
/// and can decay to a std::pair, but is really a pair of references
template <typename ItA, typename ItB>
struct pair_view {
typedef typename ItA::value_type first_type;
typedef typename ItB::value_type second_type;
typedef std::pair<first_type, second_type> pair_type;
pair_view() {}
pair_view(const ItA &a, const ItB &b):
first(*a), second(*b) {}
pair_view &operator=(const pair_view &x)
{ first = x.first; second = x.second; return *this; }
pair_view &operator=(const pair_type &x)
{ first = x.first; second = x.second; return *this; }
typename ItA::reference first;
typename ItB::reference second;
operator pair_type() const
{ return std::make_pair(first, second); }
friend bool operator==(const pair_view &a, const pair_view &b)
{ return (a.first == b.first) && (a.second == b.second); }
friend bool operator<(const pair_view &a, const pair_view &b)
{ return (a.first < b.first) || ((a.first == b.first) && (a.second < b.second)); }
friend bool operator!=(const pair_view &a, const pair_view &b)
{ return !(a == b); }
friend bool operator>(const pair_view &a, const pair_view &b)
{ return (b < a); }
friend bool operator<=(const pair_view &a, const pair_view &b)
{ return !(b < a); }
friend bool operator>=(const pair_view &a, const pair_view &b)
{ return !(a < b); }
friend bool operator==(const pair_view &a, const pair_type &b)
{ return (a.first == b.first) && (a.second == b.second); }
friend bool operator<(const pair_view &a, const pair_type &b)
{ return (a.first < b.first) || ((a.first == b.first) && (a.second < b.second)); }
friend bool operator!=(const pair_view &a, const pair_type &b)
{ return !(a == b); }
friend bool operator>(const pair_view &a, const pair_type &b)
{ return (b < a); }
friend bool operator<=(const pair_view &a, const pair_type &b)
{ return !(b < a); }
friend bool operator>=(const pair_view &a, const pair_type &b)
{ return !(a < b); }
friend bool operator==(const pair_type &a, const pair_type &b)
{ return (a.first == b.first) && (a.second == b.second); }
friend bool operator<(const pair_type &a, const pair_type &b)
{ return (a.first < b.first) || ((a.first == b.first) && (a.second < b.second)); }
friend bool operator!=(const pair_type &a, const pair_type &b)
{ return !(a == b); }
friend bool operator>(const pair_type &a, const pair_type &b)
{ return (b < a); }
friend bool operator<=(const pair_type &a, const pair_type &b)
{ return !(b < a); }
friend bool operator>=(const pair_type &a, const pair_type &b)
{ return !(a < b); }
};
template <typename ItA, typename ItB>
struct paired_iterator {
// --- standard iterator traits
typedef typename pair_view<ItA, ItB>::pair_type value_type;
typedef pair_view<ItA, ItB> reference;
typedef paired_iterator<ItA,ItB> pointer;
typedef typename std::iterator_traits<ItA>::difference_type difference_type;
typedef std::random_access_iterator_tag iterator_category;
// --- methods not required by the Random Access Iterator concept
paired_iterator(const ItA &a, const ItB &b):
a(a), b(b) {}
// --- iterator requirements
// default construction
paired_iterator() {}
// copy construction and assignment
paired_iterator(const paired_iterator &x):
a(x.a), b(x.b) {}
paired_iterator &operator=(const paired_iterator &x)
{ a = x.a; b = x.b; return *this; }
// pre- and post-increment
paired_iterator &operator++()
{ ++a; ++b; return *this; }
paired_iterator operator++(int)
{ paired_iterator tmp(*this); ++(*this); return tmp; }
// pre- and post-decrement
paired_iterator &operator--()
{ --a; --b; return *this; }
paired_iterator operator--(int)
{ paired_iterator tmp(*this); --(*this); return tmp; }
// arithmetic
paired_iterator &operator+=(const difference_type &n)
{ a += n; b += n; return *this; }
friend paired_iterator operator+(const paired_iterator &x, const difference_type &n)
{ return paired_iterator(x.a+n, x.b+n); }
friend paired_iterator operator+(const difference_type &n, const paired_iterator &x)
{ return paired_iterator(x.a+n, x.b+n); }
paired_iterator &operator-=(const difference_type &n)
{ a -= n; b -= n; return *this; }
friend paired_iterator operator-(const paired_iterator &x, const difference_type &n)
{ return paired_iterator(x.a-n, x.b-n); }
friend difference_type operator-(const paired_iterator &x, const paired_iterator &y)
{ return (x.a - y.a); }
// (in-)equality and ordering
friend bool operator==(const paired_iterator &x, const paired_iterator &y)
{ return (x.a == y.a) && (x.b == y.b); }
friend bool operator<(const paired_iterator &x, const paired_iterator &y)
{ return (x.a < y.a); }
// derived (in-)equality and ordering operators
friend bool operator!=(const paired_iterator &x, const paired_iterator &y)
{ return !(x == y); }
friend bool operator>(const paired_iterator &x, const paired_iterator &y)
{ return (y < x); }
friend bool operator<=(const paired_iterator &x, const paired_iterator &y)
{ return !(y < x); }
friend bool operator>=(const paired_iterator &x, const paired_iterator &y)
{ return !(x < y); }
// dereferencing and random access
reference operator*() const
{ return reference(a,b); }
reference operator[](const difference_type &n) const
{ return reference(a+n, b+n); }
private:
ItA a;
ItB b;
};
template <typename ItA, typename ItB>
paired_iterator<ItA, ItB> make_paired_iterator(const ItA &a, const ItB &b)
{ return paired_iterator<ItA, ItB>(a, b); }
#endif
#include <vector>
#include <algorithm>
#include <iostream>
template <typename ItA, typename ItB>
void print_kvs(const ItA &k0, const ItB &v0, const ItA &kn, const ItB &vn) {
ItA k(k0);
ItB v(v0);
while (k != kn || v != vn) {
if (k != kn && v != vn)
std::cout << "[" << *k << "] = " << *v << "\n";
else if (k != kn)
std::cout << "[" << *k << "]\n";
else if (v != vn)
std::cout << "[?] = " << *v << "\n";
if (k != kn) ++k;
if (v != vn) ++v;
}
std::cout << std::endl;
}
int main() {
std::vector<int> keys;
std::vector<std::string> data;
keys.push_back(0); data.push_back("zero");
keys.push_back(1); data.push_back("one");
keys.push_back(2); data.push_back("two");
keys.push_back(3); data.push_back("three");
keys.push_back(4); data.push_back("four");
keys.push_back(5); data.push_back("five");
keys.push_back(6); data.push_back("six");
keys.push_back(7); data.push_back("seven");
keys.push_back(8); data.push_back("eight");
keys.push_back(9); data.push_back("nine");
print_kvs(keys.begin(), data.begin(), keys.end(), data.end());
std::cout << "Shuffling\n";
std::random_shuffle(
make_paired_iterator(keys.begin(), data.begin()),
make_paired_iterator(keys.end(), data.end())
);
print_kvs(keys.begin(), data.begin(), keys.end(), data.end());
std::cout << "Sorting\n";
std::sort(
make_paired_iterator(keys.begin(), data.begin()),
make_paired_iterator(keys.end(), data.end())
);
print_kvs(keys.begin(), data.begin(), keys.end(), data.end());
std::cout << "Sort descending\n";
std::sort(
make_paired_iterator(keys.begin(), data.begin()),
make_paired_iterator(keys.end(), data.end()),
std::greater< std::pair<int,std::string> >()
);
print_kvs(keys.begin(), data.begin(), keys.end(), data.end());
return 0;
}