реализовать итератор для каждого элемента контейнеров значений для каждого ключа карты, используя итератор повышения

Как реализовать итератор только для значений карты / unordered_map, используя boost :: iterator_adaptor? Я пробовал следующий код, но он не работает из-за строки с комментарием.
Есть ли решение, чтобы избежать проблемы?

Вопрос здесь немного отличается от примера адаптера map_values, показанного в буст-коде, поскольку здесь поле значения на карте представляет собой другой контейнер, такой как список или вектор, и здесь требуется перебирать все элементы этих списков для каждого ключа карты.
Разыскивание итератора относится к типу value_type этих списков / векторов. Конец итератора — это конец списка последнего ключа.

#include <vector>
#include <boost/unordered_map.hpp>
#include <cassert>
#include <iostream>
#include <boost/iterator/iterator_adaptor.hpp>class DS {
public:
DS() : _map() {}

~DS() {
for (Map::iterator it = _map.begin(); it != _map.end(); ++it) {
delete (it->second);
}
}

void add(int key_, const std::vector< int > &value_)
{
IntList *ptr = new IntList(value_);
assert(ptr);

_map.insert(Map::value_type(key_, ptr));
}

private:
typedef std::vector< int > IntList;
typedef boost::unordered_map< int, IntList* > Map;

Map      _map;

public:
class KeyIter : public boost::iterator_adaptor< KeyIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
KeyIter() : KeyIter::iterator_adaptor_() {}

private:

friend class DS;
friend class boost::iterator_core_access;

explicit KeyIter(Map::const_iterator it) : KeyIter::iterator_adaptor_(it) {}
explicit KeyIter(Map::iterator       it) : KeyIter::iterator_adaptor_(it) {}

int        dereference() const { return this->base()->first; }
};

class ValueIter : public boost::iterator_adaptor< ValueIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
ValueIter()
: ValueIter::iterator_adaptor_()
, _lIt()
{}

private:
friend class DS;
friend class boost::iterator_core_access;

explicit ValueIter(Map::const_iterator it)
: ValueIter::iterator_adaptor_(it)
, _lIt()
, _mIt(it)
{
IntList *pt = it->second; // <<-- issue here is I can't find if I've already reached the end of the map
if (pt) {
_lIt = it->second->begin();
}
}

int                dereference() const { return *_lIt; }
void               increment()
{
if (_lIt == _mIt->second->end()) {
++_mIt;
_lIt = _mIt->second->begin();
} else {
++_lIt;
}
}

IntList::iterator        _lIt;
Map::const_iterator      _mIt;
};

KeyIter       beginKey() const { return KeyIter(_map.begin()); }
KeyIter       endKey()   const { return KeyIter(_map.end());  }
ValueIter     beginValue() const { return ValueIter(_map.begin()); }
ValueIter     endValue()   const { return ValueIter(_map.end());   }
};
int main(int argc, char** argv)
{

DS ds;

std::vector< int > v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(50);

ds.add(90, v1);

std::vector< int > v2;
v2.push_back(20);
v2.push_back(40);
v2.push_back(60);

ds.add(120, v2);

std::cout << "------------ keys ---------------" << std::endl;
for (DS::KeyIter it = ds.beginKey(); it != ds.endKey(); ++it) {
std::cout << (*it) << std::endl;
}

std::cout << "------------ values ---------------" << std::endl;
// std::cout << (*(ds.beginValue())) << std::endl;
for (DS::ValueIter it = ds.beginValue(); it != ds.endValue(); ++it) {
std::cout << (*it) << std::endl;
}

return 0;
}

0

Решение

Реализовано в C ++ 11. Вы должны быть в состоянии сделать преобразование в boost / c ++ 03 довольно просто.

Этот итератор ТОЛЬКО ВПЕРЕД и довольно хрупок (см. Оператор сравнения).

по усмотрению пользователя.

#include <iostream>
#include <vector>
#include <unordered_map>

typedef std::vector< int > IntList;
typedef std::unordered_map< int, IntList* > Map;

struct whole_map_const_iterator
{
using C1 = IntList;
using C2 = Map;

using I1 = C1::const_iterator;
using I2 = C2::const_iterator;

using value_type = I1::value_type;
using reference = I1::reference;

whole_map_const_iterator(I2 i2) : _i2(i2) {}

bool operator==(const whole_map_const_iterator& r) const {
if (_i2 != r._i2)
return false;

if (deferred_i1 && r.deferred_i1)
return true;

if (deferred_i1 != r.deferred_i1)
return false;

return _i1 == r._i1;
}
bool operator!=(const whole_map_const_iterator& r) const { return !(*this == r); }

reference operator*() const {
check_deferred();
return *_i1;
}

void check_deferred() const {
if (deferred_i1) {
_i1 = _i2->second->begin();
_i1limit = _i2->second->end();
deferred_i1 = false;
}
}

void go_next()
{
check_deferred();
if (++_i1 == _i1limit) {
++_i2;
deferred_i1 = true;
}
}

whole_map_const_iterator& operator++() {
go_next();
return *this;
}

whole_map_const_iterator operator++(int) {
auto result = *this;
go_next();
return result;
}

I2 _i2;
mutable I1 _i1 = {}, _i1limit = {};
mutable bool deferred_i1 = true;

};

IntList a { 1, 2, 3, 4, 5 };
IntList b { 6, 7, 8, 9, 10 };
Map m { { 1, &a }, { 2, &b } };int main()
{
using namespace std;
auto from = whole_map_const_iterator(m.begin());
auto to = whole_map_const_iterator(m.end());
for ( ; from != to ; ++from) {
std::cout << *from << std::endl;
}
return 0;
}

пример вывода:

6
7
8
9
10
1
2
3
4
5

Для получения бонусных баллов ответьте на этот вопрос:

Q: Почему все эти чертовы сложности из-за отложенного флага?

1

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector