STL-карта на себя?
Я хотел бы создать std::map
, который содержит итераторы std::vector
для себя, для реализации простой структуры графства на основе смежности.
Однако объявление типа имеет тупик: кажется, вам нужно определение всего типа карты, чтобы получить тип итератора указанной карты, например:
map< int, Something >::iterator MyMap_it; // what should Something be?
map< int, vector<MyMap_it> > MyMap_t;
Есть ли какой-то тип итератора частичного отображения, который я могу получить только с типом ключа, поэтому я могу объявить полную карту?
Ответы
Ответ 1
Вы можете использовать форвардное объявление нового типа.
class MapItContainers;
typedef map<int, MapItContainers>::iterator MyMap_it;
class MapItContainers
{
public:
vector<MyMap_it> vec;
};
С этой косвенностью компилятор должен позволить вам с этим справиться.
Это не очень мило, но, честно говоря, я не думаю, что вы можете легко сломать себе ссылку.
Ответ 2
Не слишком уродливо, учитывая...
Это работает в 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;
}
Ответ 3
Мне не нравилось получение из контейнера в моем предыдущем ответе, так что вот альтернатива:
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
. Слишком плохо С++ не позволяет шаблонам шаблонов.
Использование производного типа итератора должно быть ОК. Вы все равно можете инициализировать обратный итератор из элемента этой структуры, например.
Ответ 4
В дополнение к ответу на 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;
Кроме того, здесь обновление (мое любимое до сих пор) для С++ 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;