Вопрос

Я хотел бы создать std::map, содержащий в себе std::vector итераторов, для реализации простой структуры графа на основе списка смежности.

Однако объявление типа поставило меня в тупик: может показаться, что вам нужно полное определение типа карты, чтобы получить тип итератора для указанной карты, например:

map< int, Something >::iterator MyMap_it;  // what should Something be?
map< int, vector<MyMap_it> > MyMap_t;

Есть ли какой-то тип итератора частичной карты, который я могу получить только с помощью типа ключа, чтобы я мог объявить полную карту?

Это было полезно?

Решение

Вы можете использовать предварительное объявление нового типа.

class MapItContainers;
typedef map<int, MapItContainers>::iterator MyMap_it;

class MapItContainers
{
public:
 vector<MyMap_it> vec;
};

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

Другие советы

Не так страшно, учитывая & # 8230;

Это работает в GCC 4.0.1 и прекрасно компилируется в строгом режиме Comeau.

Определения шаблонов анализируются и откладываются до момента их создания. Компилятор даже не видит, что такое rec_map_iterator, пока не пришло время его создать, и к тому времени он уже знает, как это сделать; v).

template< class key >
struct rec_map;

template< class key >
struct rec_map_iterator : rec_map< key >::iterator {
    rec_map_iterator( typename rec_map< key >::iterator i)
    : rec_map< key >::iterator(i) {}
};

template< class key >
struct rec_map : map< key, vector< rec_map_iterator< key > > > {};

Вот тестовая программа, которую я использовал.

#include <iostream>
#include <map>
#include <vector>

using namespace std;

template< class key >
struct rec_map;

template< class key >
struct rec_map_iterator : rec_map< key >::iterator {
    rec_map_iterator( typename rec_map< key >::iterator i)
    : rec_map< key >::iterator(i) {}
};

template< class key >
struct rec_map : map< key, vector< rec_map_iterator< key > > > {};

int main( int argc, char ** argv ) {
    rec_map< int > my_map;

    my_map[4];
    my_map[6].push_back( my_map.begin() );

    cerr << my_map[6].front()->first << endl;

    return 0;
}

Мне не понравилось получение из контейнера в моем предыдущем ответе, так что вот альтернатива:

template< class key >
struct rec_map_gen {
    struct i;
    typedef map< key, vector< i > > t;
    struct i : t::iterator {
        i( typename t::iterator v )
        : t::iterator(v) {}
    };
};

Теперь вы должны использовать rec_map_gen<int>::t, rec_map_gen<int>::t::iterator и т. д., но у вас также есть доступ ко всем конструкторам std::map. Жаль, что C ++ не позволяет шаблонизировать шаблоны.

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

В дополнение к ответу Potatoswatter, если вы не возражаете против необходимости ссылаться на весь шаблонный тип карты несколько раз, вам нужно только создать подкласс итератора и не требовать никаких предварительных объявлений:

template<class key>
struct rec_map_iterator : map<key, vector<rec_map_iterator<key> > >::iterator
{
    rec_map_iterator(typename map<key, vector<rec_map_iterator<key> > >::iterator i)
        : map<key, vector<rec_map_iterator<key> > >::iterator(i)
    {}
};

Затем используйте полный тип:

map<int, vector<rec_map_iterator<int>>> m;

Кроме того, вот обновление (мое любимое на данный момент) для C ++ 11, объявив rec_map в качестве псевдонима, который может быть шаблонным:

template<class key>
struct rec_map_iterator;

template<class key>
using rec_map = map<key, vector<rec_map_iterator<key>>>;

template<class key>
struct rec_map_iterator : rec_map<key>::iterator
{
    rec_map_iterator(typename rec_map<key>::iterator i)
        : rec_map<key>::iterator(i)
    {}
};

Это работает так же, как версия Potatoswatter:

rec_map<int> my_map;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top