2009-09-10 39 views
12

我想创建一个std::map包含迭代器本身的std::vector,实现一个简单的基于列表的邻接图结构。STL地图本身?

然而,类型声明有我难住了:这似乎需要整个地图类型定义,以获得迭代器类型的表示图,就像这样:

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

是否有某种形式的部分地图迭代我只能使用键类型获得类型,所以我可以声明完整的地图?

+2

Interesting..sounds像无限递归。 – Naveen 2009-09-10 05:32:57

+0

这就是我的想法。 – GManNickG 2009-09-10 05:38:42

+1

只是一个循环指针......除非map <> :: iterator试图用它的类型参数做一些有意义的事情,否则不会有递归。这对于它来说是完全合法的,只是在GCC + SGI STL中不会发生。 – Potatoswatter 2009-09-10 07:05:26

回答

14

您可以使用新类型的前向声明。

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

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

有了这种间接方式,编译器应该让你脱身。 这不是很漂亮,但老实说,我不认为你可以轻松地打破自我引用。

+0

gcc 4.4.1看起来不是在这个barf,它甚至让我创建'map '的实例。 – Omnifarious 2009-09-10 06:07:10

+0

可能因为迭代器只使用指向第二个模板参数类型的指针/引用,所以前向声明就足够了。 – Kos 2011-12-20 01:10:49

5

不太丑,考虑...

这个工作在GCC 4.0.1和科莫严格模式编译罚款。

模板定义进行分析和推迟,直到他们被实例化。编译器甚至没有看到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; 
} 
+0

+1令我害怕。尽管如此,我不会在生产代码中使用它,但nasmorns解决方案要简单得多。 – hirschhornsalz 2009-09-10 07:24:11

+0

我可以让你编写更简单的代码,除了一次性的诡计。也许不那么优雅,但我认为它更符合C++的精神; v)。 – Potatoswatter 2009-09-10 07:32:27

+0

为什么模板 struct rec_map_iterator:rec_map :: iterator'需要在'rec_map :: iterator'前面加上'typename'?基本初始化列表也是如此。 (FWIW,科莫同意你的GCC,但我不明白为什么会这样)。 – sbi 2009-09-10 08:37:44

2

我不喜欢在我以前的答案从容器中派生所以这里的一种替代方案:

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>::trec_map_gen<int>::t::iterator,等等,但你也可以访问所有std::map的构造函数。这太糟糕了,C++不允许typedefs模板化。

使用派生迭代器类型应该没问题。例如,您仍然可以从此结构的元素初始化反向迭代器。

2

除了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) 
    {} 
}; 
通过声明rec_map作为一个别名,它可以作为模板

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

而且,这里是一个更新(我的最爱到目前为止)对C++ 11:

然后使用完整的类型3210

这个工程一样Potatoswatter的版本:

rec_map<int> my_map; 
+0

这是类似于我*第二*答案:)但C++ 11因子更好。 – Potatoswatter 2017-01-30 13:34:28